19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text.method; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brownimport android.text.Editable; 20497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brownimport android.text.NoCopySpan; 21497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brownimport android.text.Spannable; 22497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brownimport android.text.Spanned; 234037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport android.view.KeyCharacterMap; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 286b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * This base class encapsulates the behavior for tracking the state of 296b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * meta keys such as SHIFT, ALT and SYM as well as the pseudo-meta state of selecting text. 306b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * <p> 316b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * Key listeners that care about meta state should inherit from this class; 326b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * you should not instantiate this class directly in a client. 336b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </p><p> 346b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * This class provides two mechanisms for tracking meta state that can be used 356b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * together or independently. 366b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </p> 376b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * <ul> 386b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * <li>Methods such as {@link #handleKeyDown(long, int, KeyEvent)} and 396b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * {@link #getMetaState(long)} operate on a meta key state bit mask.</li> 406b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * <li>Methods such as {@link #onKeyDown(View, Editable, int, KeyEvent)} and 416b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * {@link #getMetaState(CharSequence, int)} operate on meta key state flags stored 426b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * as spans in an {@link Editable} text buffer. The spans only describe the current 436b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * meta key state of the text editor; they do not carry any positional information.</li> 446b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </ul> 456b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * <p> 466b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * The behavior of this class varies according to the keyboard capabilities 476b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * described by the {@link KeyCharacterMap} of the keyboard device such as 486b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * the {@link KeyCharacterMap#getModifierBehavior() key modifier behavior}. 496b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </p><p> 506b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * {@link MetaKeyKeyListener} implements chorded and toggled key modifiers. 516b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * When key modifiers are toggled into a latched or locked state, the state 526b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * of the modifier is stored in the {@link Editable} text buffer or in a 536b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * meta state integer managed by the client. These latched or locked modifiers 546b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * should be considered to be held <b>in addition to</b> those that the 556b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * keyboard already reported as being pressed in {@link KeyEvent#getMetaState()}. 566b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * In other words, the {@link MetaKeyKeyListener} augments the meta state 576b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * provided by the keyboard; it does not replace it. This distinction is important 586b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * to ensure that meta keys not handled by {@link MetaKeyKeyListener} such as 596b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * {@link KeyEvent#KEYCODE_CAPS_LOCK} or {@link KeyEvent#KEYCODE_NUM_LOCK} are 606b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * taken into consideration. 616b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </p><p> 626b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * To ensure correct meta key behavior, the following pattern should be used 636b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * when mapping key codes to characters: 646b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </p> 656b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * <code> 666b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * private char getUnicodeChar(TextKeyListener listener, KeyEvent event, Editable textBuffer) { 676b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * // Use the combined meta states from the event and the key listener. 686b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * int metaState = event.getMetaState() | listener.getMetaState(textBuffer); 696b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * return event.getUnicodeChar(metaState); 706b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * } 716b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown * </code> 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class MetaKeyKeyListener { 74497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 75497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Flag that indicates that the SHIFT key is on. 76497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Value equals {@link KeyEvent#META_SHIFT_ON}. 77497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int META_SHIFT_ON = KeyEvent.META_SHIFT_ON; 79497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 80497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Flag that indicates that the ALT key is on. 81497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Value equals {@link KeyEvent#META_ALT_ON}. 82497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int META_ALT_ON = KeyEvent.META_ALT_ON; 84497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 85497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Flag that indicates that the SYM key is on. 86497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Value equals {@link KeyEvent#META_SYM_ON}. 87497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int META_SYM_ON = KeyEvent.META_SYM_ON; 894037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 90497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 91497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Flag that indicates that the SHIFT key is locked in CAPS mode. 92497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 93497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown public static final int META_CAP_LOCKED = KeyEvent.META_CAP_LOCKED; 94497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 95497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Flag that indicates that the ALT key is locked. 96497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 97497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown public static final int META_ALT_LOCKED = KeyEvent.META_ALT_LOCKED; 98497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 99497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Flag that indicates that the SYM key is locked. 100497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 101497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown public static final int META_SYM_LOCKED = KeyEvent.META_SYM_LOCKED; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API review 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 106497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown public static final int META_SELECTING = KeyEvent.META_SELECTING; 107497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 108497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown // These bits are privately used by the meta key key listener. 109497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown // They are deliberately assigned values outside of the representable range of an 'int' 110497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown // so as not to conflict with any meta key states publicly defined by KeyEvent. 111497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_CAP_USED = 1L << 32; 112497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_ALT_USED = 1L << 33; 113497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_SYM_USED = 1L << 34; 1144037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 115497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_CAP_PRESSED = 1L << 40; 116497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_ALT_PRESSED = 1L << 41; 117497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_SYM_PRESSED = 1L << 42; 1184037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 119497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_CAP_RELEASED = 1L << 48; 120497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_ALT_RELEASED = 1L << 49; 121497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static final long META_SYM_RELEASED = 1L << 50; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final long META_SHIFT_MASK = META_SHIFT_ON 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | META_CAP_LOCKED | META_CAP_USED 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | META_CAP_PRESSED | META_CAP_RELEASED; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final long META_ALT_MASK = META_ALT_ON 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | META_ALT_LOCKED | META_ALT_USED 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | META_ALT_PRESSED | META_ALT_RELEASED; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final long META_SYM_MASK = META_SYM_ON 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | META_SYM_LOCKED | META_SYM_USED 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | META_SYM_PRESSED | META_SYM_RELEASED; 1324037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Object CAP = new NoCopySpan.Concrete(); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Object ALT = new NoCopySpan.Concrete(); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Object SYM = new NoCopySpan.Concrete(); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Object SELECTING = new NoCopySpan.Concrete(); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 138f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard private static final int PRESSED_RETURN_VALUE = 1; 139f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard private static final int LOCKED_RETURN_VALUE = 2; 140f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Resets all meta state to inactive. 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void resetMetaState(Spannable text) { 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text.removeSpan(CAP); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text.removeSpan(ALT); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text.removeSpan(SYM); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text.removeSpan(SELECTING); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the state of the meta keys. 1534037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas * 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param text the buffer in which the meta key would have been pressed. 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return an integer in which each bit set to one represents a pressed 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or locked meta key. 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int getMetaState(CharSequence text) { 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getActive(text, CAP, META_SHIFT_ON, META_CAP_LOCKED) | 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getActive(text, ALT, META_ALT_ON, META_ALT_LOCKED) | 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getActive(text, SYM, META_SYM_ON, META_SYM_LOCKED) | 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getActive(text, SELECTING, META_SELECTING, META_SELECTING); 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16614f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien /** 16714f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * Gets the state of the meta keys for a specific key event. 16814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * 16914f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * For input devices that use toggled key modifiers, the `toggled' state 17014f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * is stored into the text buffer. This method retrieves the meta state 17114f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * for this event, accounting for the stored state. If the event has been 17214f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * created by a device that does not support toggled key modifiers, like 17314f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * a virtual device for example, the stored state is ignored. 17414f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * 17514f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @param text the buffer in which the meta key would have been pressed. 17614f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @param event the event for which to evaluate the meta state. 17714f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @return an integer in which each bit set to one represents a pressed 17814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * or locked meta key. 17914f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien */ 18014f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien public static final int getMetaState(final CharSequence text, final KeyEvent event) { 18114f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien int metaState = event.getMetaState(); 18214f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien if (event.getKeyCharacterMap().getModifierBehavior() 18314f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) { 18414f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien metaState |= getMetaState(text); 18514f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien } 18614f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien return metaState; 18714f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien } 18814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien 189f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard // As META_SELECTING is @hide we should not mention it in public comments, hence the 190f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard // omission in @param meta 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the state of a particular meta key. 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 194f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param text the buffer in which the meta key would have been pressed. 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 0 if inactive, 1 if active, 2 if locked. 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int getMetaState(CharSequence text, int meta) { 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (meta) { 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_SHIFT_ON: 202f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard return getActive(text, CAP, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_ALT_ON: 205f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard return getActive(text, ALT, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_SYM_ON: 208f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard return getActive(text, SYM, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_SELECTING: 211f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard return getActive(text, SELECTING, PRESSED_RETURN_VALUE, LOCKED_RETURN_VALUE); 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien /** 21914f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * Gets the state of a particular meta key to use with a particular key event. 22014f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * 22114f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * If the key event has been created by a device that does not support toggled 22214f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * key modifiers, like a virtual keyboard for example, only the meta state in 22314f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * the key event is considered. 22414f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * 22514f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON 22614f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @param text the buffer in which the meta key would have been pressed. 22714f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @param event the event for which to evaluate the meta state. 22814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien * @return 0 if inactive, 1 if active, 2 if locked. 22914f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien */ 23014f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien public static final int getMetaState(final CharSequence text, final int meta, 23114f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien final KeyEvent event) { 23214f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien int metaState = event.getMetaState(); 23314f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien if (event.getKeyCharacterMap().getModifierBehavior() 23414f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) { 23514f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien metaState |= getMetaState(text); 23614f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien } 23714f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien if (META_SELECTING == meta) { 23814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien // #getMetaState(long, int) does not support META_SELECTING, but we want the same 23914f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien // behavior as #getMetaState(CharSequence, int) so we need to do it here 24014f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien if ((metaState & META_SELECTING) != 0) { 24114f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien // META_SELECTING is only ever set to PRESSED and can't be LOCKED, so return 1 24214f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien return 1; 24314f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien } 24414f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien return 0; 24514f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien } 24614f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien return getMetaState(metaState, meta); 24714f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien } 24814f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int getActive(CharSequence text, Object meta, 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int on, int lock) { 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!(text instanceof Spanned)) { 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) text; 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int flag = sp.getSpanFlags(meta); 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (flag == LOCKED) { 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return lock; 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (flag != 0) { 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return on; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call this method after you handle a keypress so that the meta 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * state will be reset to unshifted (if it is not still down) 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or primed to be reset to unshifted (once it is released). 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void adjustMetaAfterKeypress(Spannable content) { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjust(content, CAP); 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjust(content, ALT); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjust(content, SYM); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns true if this object is one that this class would use to 280b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project * keep track of any meta state in the specified text. 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean isMetaTracker(CharSequence text, Object what) { 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return what == CAP || what == ALT || what == SYM || 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project what == SELECTING; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 287b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project /** 288b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project * Returns true if this object is one that this class would use to 289b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project * keep track of the selecting meta state in the specified text. 290b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project */ 291b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project public static boolean isSelectingMetaTracker(CharSequence text, Object what) { 292b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project return what == SELECTING; 293b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project } 294b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void adjust(Spannable content, Object what) { 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int current = content.getSpanFlags(what); 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (current == PRESSED) 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(what, 0, 0, USED); 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (current == RELEASED) 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(what); 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call this if you are a method that ignores the locked meta state 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (arrow keys, for example) and you handle a key. 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected static void resetLockedMeta(Spannable content) { 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetLock(content, CAP); 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetLock(content, ALT); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetLock(content, SYM); 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetLock(content, SELECTING); 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void resetLock(Spannable content, Object what) { 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int current = content.getSpanFlags(what); 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (current == LOCKED) 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(what); 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handles presses of the meta keys. 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3256b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) { 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project press(content, CAP); 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || keyCode == KeyEvent.KEYCODE_NUM) { 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project press(content, ALT); 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SYM) { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project press(content, SYM); 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; // no super to call through to 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void press(Editable content, Object what) { 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int state = content.getSpanFlags(what); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (state == PRESSED) 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ; // repeat before use 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (state == RELEASED) 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(what, 0, 0, LOCKED); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (state == USED) 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ; // repeat after use 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (state == LOCKED) 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(what); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(what, 0, 0, PRESSED); 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Start selecting text. 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API review 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void startSelecting(View view, Spannable content) { 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(SELECTING, 0, 0, PRESSED); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stop selecting text. This does not actually collapse the selection; 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * call {@link android.text.Selection#setSelection} too. 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API review 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void stopSelecting(View view, Spannable content) { 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(SELECTING); 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handles release of the meta keys. 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3806b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown public boolean onKeyUp(View view, Editable content, int keyCode, KeyEvent event) { 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { 3826b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown release(content, CAP, event); 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || keyCode == KeyEvent.KEYCODE_NUM) { 3886b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown release(content, ALT, event); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SYM) { 3936b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown release(content, SYM, event); 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; // no super to call through to 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4006b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown private void release(Editable content, Object what, KeyEvent event) { 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int current = content.getSpanFlags(what); 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4036b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown switch (event.getKeyCharacterMap().getModifierBehavior()) { 4046b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown case KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED: 4056b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown if (current == USED) 4066b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown content.removeSpan(what); 4076b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown else if (current == PRESSED) 4086b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown content.setSpan(what, 0, 0, RELEASED); 4096b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown break; 4106b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown 4116b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown default: 4126b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown content.removeSpan(what); 4136b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown break; 4146b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown } 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clearMetaKeyState(View view, Editable content, int states) { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearMetaKeyState(content, states); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void clearMetaKeyState(Editable content, int states) { 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((states&META_SHIFT_ON) != 0) content.removeSpan(CAP); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((states&META_ALT_ON) != 0) content.removeSpan(ALT); 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((states&META_SYM_ON) != 0) content.removeSpan(SYM); 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((states&META_SELECTING) != 0) content.removeSpan(SELECTING); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call this if you are a method that ignores the locked meta state 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (arrow keys, for example) and you handle a key. 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long resetLockedMeta(long state) { 433497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_CAP_LOCKED) != 0) { 434497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_SHIFT_MASK; 435497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 436497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_ALT_LOCKED) != 0) { 437497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_ALT_MASK; 438497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 439497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_SYM_LOCKED) != 0) { 440497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_SYM_MASK; 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // --------------------------------------------------------------------- 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Version of API that operates on a state bit mask 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // --------------------------------------------------------------------- 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the state of the meta keys. 4514037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas * 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param state the current meta state bits. 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return an integer in which each bit set to one represents a pressed 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or locked meta key. 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int getMetaState(long state) { 458497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown int result = 0; 459497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 460497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_CAP_LOCKED) != 0) { 461497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown result |= META_CAP_LOCKED; 462497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & META_SHIFT_ON) != 0) { 463497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown result |= META_SHIFT_ON; 464497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 465497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 466497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_ALT_LOCKED) != 0) { 467497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown result |= META_ALT_LOCKED; 468497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & META_ALT_ON) != 0) { 469497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown result |= META_ALT_ON; 470497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 471497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 472497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_SYM_LOCKED) != 0) { 473497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown result |= META_SYM_LOCKED; 474497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & META_SYM_ON) != 0) { 475497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown result |= META_SYM_ON; 476497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 477497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 478497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return result; 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the state of a particular meta key. 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param state the current state bits. 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param meta META_SHIFT_ON, META_ALT_ON, or META_SYM_ON 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return 0 if inactive, 1 if active, 2 if locked. 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int getMetaState(long state, int meta) { 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (meta) { 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_SHIFT_ON: 492f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard if ((state & META_CAP_LOCKED) != 0) return LOCKED_RETURN_VALUE; 493f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard if ((state & META_SHIFT_ON) != 0) return PRESSED_RETURN_VALUE; 494497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return 0; 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_ALT_ON: 497f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard if ((state & META_ALT_LOCKED) != 0) return LOCKED_RETURN_VALUE; 498f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard if ((state & META_ALT_ON) != 0) return PRESSED_RETURN_VALUE; 499497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return 0; 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case META_SYM_ON: 502f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard if ((state & META_SYM_LOCKED) != 0) return LOCKED_RETURN_VALUE; 503f9bd5f69e2b540bbd3187fe1d7c7ca33f77f0cd9Jean Chalard if ((state & META_SYM_ON) != 0) return PRESSED_RETURN_VALUE; 504497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return 0; 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call this method after you handle a keypress so that the meta 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * state will be reset to unshifted (if it is not still down) 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or primed to be reset to unshifted (once it is released). Takes 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the current state, returns the new state. 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long adjustMetaAfterKeypress(long state) { 518497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_CAP_PRESSED) != 0) { 519497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state = (state & ~META_SHIFT_MASK) | META_SHIFT_ON | META_CAP_USED; 520497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & META_CAP_RELEASED) != 0) { 521497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_SHIFT_MASK; 522497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 523497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 524497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_ALT_PRESSED) != 0) { 525497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state = (state & ~META_ALT_MASK) | META_ALT_ON | META_ALT_USED; 526497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & META_ALT_RELEASED) != 0) { 527497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_ALT_MASK; 528497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 530497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & META_SYM_PRESSED) != 0) { 531497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state = (state & ~META_SYM_MASK) | META_SYM_ON | META_SYM_USED; 532497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & META_SYM_RELEASED) != 0) { 533497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_SYM_MASK; 534497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handles presses of the meta keys. 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long handleKeyDown(long state, int keyCode, KeyEvent event) { 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { 543497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return press(state, META_SHIFT_ON, META_SHIFT_MASK, 544497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown META_CAP_LOCKED, META_CAP_PRESSED, META_CAP_RELEASED, META_CAP_USED); 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || keyCode == KeyEvent.KEYCODE_NUM) { 549497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return press(state, META_ALT_ON, META_ALT_MASK, 550497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown META_ALT_LOCKED, META_ALT_PRESSED, META_ALT_RELEASED, META_ALT_USED); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SYM) { 554497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return press(state, META_SYM_ON, META_SYM_MASK, 555497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown META_SYM_LOCKED, META_SYM_PRESSED, META_SYM_RELEASED, META_SYM_USED); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 560497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static long press(long state, int what, long mask, 561497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown long locked, long pressed, long released, long used) { 562497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown if ((state & pressed) != 0) { 563497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown // repeat before use 564497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & released) != 0) { 565497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state = (state &~ mask) | what | locked; 566497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & used) != 0) { 567497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown // repeat after use 568497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else if ((state & locked) != 0) { 569497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~mask; 570497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } else { 571497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state |= what | pressed; 572497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handles release of the meta keys. 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static long handleKeyUp(long state, int keyCode, KeyEvent event) { 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { 581497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return release(state, META_SHIFT_ON, META_SHIFT_MASK, 5826b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown META_CAP_PRESSED, META_CAP_RELEASED, META_CAP_USED, event); 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || keyCode == KeyEvent.KEYCODE_NUM) { 587497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return release(state, META_ALT_ON, META_ALT_MASK, 5886b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown META_ALT_PRESSED, META_ALT_RELEASED, META_ALT_USED, event); 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_SYM) { 592497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown return release(state, META_SYM_ON, META_SYM_MASK, 5936b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown META_SYM_PRESSED, META_SYM_RELEASED, META_SYM_USED, event); 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 598497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown private static long release(long state, int what, long mask, 5996b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown long pressed, long released, long used, KeyEvent event) { 6006b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown switch (event.getKeyCharacterMap().getModifierBehavior()) { 6016b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown case KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED: 6026b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown if ((state & used) != 0) { 6036b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown state &= ~mask; 6046b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown } else if ((state & pressed) != 0) { 6056b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown state |= what | released; 6066b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown } 6076b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown break; 6086b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown 6096b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown default: 6106b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown state &= ~mask; 6116b53e8daa69cba1a2a5a7c95a01e37ce9c53226cJeff Brown break; 612497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 616497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown /** 617497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * Clears the state of the specified meta key if it is locked. 618497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * @param state the meta key state 619497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * @param which meta keys to clear, may be a combination of {@link #META_SHIFT_ON}, 620497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown * {@link #META_ALT_ON} or {@link #META_SYM_ON}. 621497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown */ 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long clearMetaKeyState(long state, int which) { 62352715a7c10eeb798692ffdb4bc8c4305cb0aa705Jeff Brown if ((which & META_SHIFT_ON) != 0 && (state & META_CAP_LOCKED) != 0) { 624497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_SHIFT_MASK; 625497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 62652715a7c10eeb798692ffdb4bc8c4305cb0aa705Jeff Brown if ((which & META_ALT_ON) != 0 && (state & META_ALT_LOCKED) != 0) { 627497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_ALT_MASK; 628497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 62952715a7c10eeb798692ffdb4bc8c4305cb0aa705Jeff Brown if ((which & META_SYM_ON) != 0 && (state & META_SYM_LOCKED) != 0) { 630497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown state &= ~META_SYM_MASK; 631497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown } 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return state; 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 634497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The meta key has been pressed but has not yet been used. 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6384037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas private static final int PRESSED = 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_MARK_MARK | (1 << Spannable.SPAN_USER_SHIFT); 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The meta key has been pressed and released but has still 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * not yet been used. 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6454037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas private static final int RELEASED = 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_MARK_MARK | (2 << Spannable.SPAN_USER_SHIFT); 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The meta key has been pressed and used but has not yet been released. 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6514037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas private static final int USED = 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_MARK_MARK | (3 << Spannable.SPAN_USER_SHIFT); 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The meta key has been pressed and released without use, and then 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pressed again; it may also have been released again. 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6584037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas private static final int LOCKED = 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_MARK_MARK | (4 << Spannable.SPAN_USER_SHIFT); 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 661