146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown/* 246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Copyright (C) 2006 The Android Open Source Project 346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * 446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * you may not use this file except in compliance with the License. 646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * You may obtain a copy of the License at 746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * 846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * 1046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Unless required by applicable law or agreed to in writing, software 1146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 1246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * See the License for the specific language governing permissions and 1446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * limitations under the License. 1546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown */ 1646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown 1746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownpackage android.text.method; 1846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown 1946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownimport android.view.KeyEvent; 20b4ff35df5c04aec71fce7e90a6d6f9ef7180c2adJeff Brownimport android.view.View; 21b4ff35df5c04aec71fce7e90a6d6f9ef7180c2adJeff Brownimport android.text.*; 22be1aa8250cee7819c49741e819e81659d1d03823Jeff Brownimport android.text.method.TextKeyListener.Capitalize; 23b4ff35df5c04aec71fce7e90a6d6f9ef7180c2adJeff Brownimport android.widget.TextView; 249d3b1a424c5c61e24e9659d15fb353026a00d925Jeff Brown 259d3b1a424c5c61e24e9659d15fb353026a00d925Jeff Brown/** 269d3b1a424c5c61e24e9659d15fb353026a00d925Jeff Brown * Abstract base class for key listeners. 2746b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * 2846b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Provides a basic foundation for entering and editing text. 2946b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * Subclasses should override {@link #onKeyDown} and {@link #onKeyUp} to insert 3046b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * characters as keys are pressed. 3146b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * <p></p> 3246b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * As for all implementations of {@link KeyListener}, this class is only concerned 3346b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * with hardware keyboards. Software input methods have no obligation to trigger 3446b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * the methods in this class. 3546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown */ 3646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brownpublic abstract class BaseKeyListener extends MetaKeyKeyListener 37a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown implements KeyListener { 38a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete(); 39a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown 40a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown /** 41a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown * Performs the action that happens when you press the {@link KeyEvent#KEYCODE_DEL} key in 42a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown * a {@link TextView}. If there is a selection, deletes the selection; otherwise, 43a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown * deletes the character before the cursor, if any; ALT+DEL deletes everything on 44a47425a13c19f95057df78b8bb65bb25657e8753Jeff Brown * the line the cursor is on. 4546b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * 4646b9ac0ae2162309774a7478cd9d4e578747bfc2Jeff Brown * @return true if anything was deleted; false otherwise. 476d0fec2de3601821f4f44eeb7d7deedebb2b7117Jeff Brown */ 486d0fec2de3601821f4f44eeb7d7deedebb2b7117Jeff Brown public boolean backspace(View view, Editable content, int keyCode, KeyEvent event) { 496d0fec2de3601821f4f44eeb7d7deedebb2b7117Jeff Brown return backspaceOrForwardDelete(view, content, keyCode, event, false); 50d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 51d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown 52d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown /** 53d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown * Performs the action that happens when you press the {@link KeyEvent#KEYCODE_FORWARD_DEL} 54d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown * key in a {@link TextView}. If there is a selection, deletes the selection; otherwise, 55d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown * deletes the character before the cursor, if any; ALT+FORWARD_DEL deletes everything on 56d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown * the line the cursor is on. 57d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown * 58d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown * @return true if anything was deleted; false otherwise. 59d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown */ 60d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown public boolean forwardDelete(View view, Editable content, int keyCode, KeyEvent event) { 61d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown return backspaceOrForwardDelete(view, content, keyCode, event, true); 62d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 63d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown 64d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown private boolean backspaceOrForwardDelete(View view, Editable content, int keyCode, 6583d616a9c7b9505153d258511eb5c16b552e268dJeff Brown KeyEvent event, boolean isForwardDelete) { 6683d616a9c7b9505153d258511eb5c16b552e268dJeff Brown // Ensure the key event does not have modifiers except ALT or SHIFT. 67d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown if (!KeyEvent.metaStateHasNoModifiers(event.getMetaState() 68d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown & ~(KeyEvent.META_SHIFT_MASK | KeyEvent.META_ALT_MASK))) { 6983d616a9c7b9505153d258511eb5c16b552e268dJeff Brown return false; 70d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 7183d616a9c7b9505153d258511eb5c16b552e268dJeff Brown 7283d616a9c7b9505153d258511eb5c16b552e268dJeff Brown // If there is a current selection, delete it. 73d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown if (deleteSelection(view, content)) { 74d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown return true; 75d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 76d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown 77d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible. 78d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown if (getMetaState(content, META_ALT_ON, event) == 1) { 79d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown if (deleteLine(view, content)) { 80d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown return true; 81d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 82d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 83d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown 84d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown // Delete a character. 8583d616a9c7b9505153d258511eb5c16b552e268dJeff Brown final int start = Selection.getSelectionEnd(content); 8683d616a9c7b9505153d258511eb5c16b552e268dJeff Brown final int end; 8783d616a9c7b9505153d258511eb5c16b552e268dJeff Brown if (isForwardDelete || event.isShiftPressed() 88d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown || getMetaState(content, META_SHIFT_ON) == 1) { 89d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown end = TextUtils.getOffsetAfter(content, start); 90d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } else { 91d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown end = TextUtils.getOffsetBefore(content, start); 92d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown } 9383d616a9c7b9505153d258511eb5c16b552e268dJeff Brown if (start != end) { 9483d616a9c7b9505153d258511eb5c16b552e268dJeff Brown content.delete(Math.min(start, end), Math.max(start, end)); 9583d616a9c7b9505153d258511eb5c16b552e268dJeff Brown return true; 9683d616a9c7b9505153d258511eb5c16b552e268dJeff Brown } 9783d616a9c7b9505153d258511eb5c16b552e268dJeff Brown return false; 9883d616a9c7b9505153d258511eb5c16b552e268dJeff Brown } 9983d616a9c7b9505153d258511eb5c16b552e268dJeff Brown 10083d616a9c7b9505153d258511eb5c16b552e268dJeff Brown private boolean deleteSelection(View view, Editable content) { 10183d616a9c7b9505153d258511eb5c16b552e268dJeff Brown int selectionStart = Selection.getSelectionStart(content); 10283d616a9c7b9505153d258511eb5c16b552e268dJeff Brown int selectionEnd = Selection.getSelectionEnd(content); 10383d616a9c7b9505153d258511eb5c16b552e268dJeff Brown if (selectionEnd < selectionStart) { 10483d616a9c7b9505153d258511eb5c16b552e268dJeff Brown int temp = selectionEnd; 10583d616a9c7b9505153d258511eb5c16b552e268dJeff Brown selectionEnd = selectionStart; 10683d616a9c7b9505153d258511eb5c16b552e268dJeff Brown selectionStart = temp; 10783d616a9c7b9505153d258511eb5c16b552e268dJeff Brown } 10883d616a9c7b9505153d258511eb5c16b552e268dJeff Brown if (selectionStart != selectionEnd) { 10983d616a9c7b9505153d258511eb5c16b552e268dJeff Brown content.delete(selectionStart, selectionEnd); 11083d616a9c7b9505153d258511eb5c16b552e268dJeff Brown return true; 11183d616a9c7b9505153d258511eb5c16b552e268dJeff Brown } 112d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown return false; 1138d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown } 1149c3cda04d969912bc46184f2b326d1db95e0aba5Jeff Brown 115214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown private boolean deleteLine(View view, Editable content) { 116214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (view instanceof TextView) { 117214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown final Layout layout = ((TextView) view).getLayout(); 118214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (layout != null) { 119214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown final int line = layout.getLineForOffset(Selection.getSelectionStart(content)); 120474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown final int start = layout.getLineStart(line); 121474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown final int end = layout.getLineEnd(line); 122474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown if (end != start) { 123474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown content.delete(start, end); 124474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown return true; 125474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown } 126474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown } 127474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown } 12865fd251c3913fc921468a3dad190810db19eb9dfJeff Brown return false; 12965fd251c3913fc921468a3dad190810db19eb9dfJeff Brown } 13065fd251c3913fc921468a3dad190810db19eb9dfJeff Brown 131daf4a127ba2af82a3fb477044b872719a0ab1827Jeff Brown static int makeTextContentType(Capitalize caps, boolean autoText) { 132daf4a127ba2af82a3fb477044b872719a0ab1827Jeff Brown int contentType = InputType.TYPE_CLASS_TEXT; 133daf4a127ba2af82a3fb477044b872719a0ab1827Jeff Brown switch (caps) { 1346ec6f79e1ac1714e3b837796e99f07ff88f66601Jeff Brown case CHARACTERS: 1356ec6f79e1ac1714e3b837796e99f07ff88f66601Jeff Brown contentType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS; 1366ec6f79e1ac1714e3b837796e99f07ff88f66601Jeff Brown break; 1375bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown case WORDS: 1385bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown contentType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS; 1395bbd4b4f5fc19302fa017ad6afee6eb2d489d91aJeff Brown break; 140474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown case SENTENCES: 141474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown contentType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; 142474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown break; 143474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown } 144214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (autoText) { 145214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown contentType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; 146214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 147214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown return contentType; 148214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 149214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 150214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown public boolean onKeyDown(View view, Editable content, 151214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown int keyCode, KeyEvent event) { 152214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown boolean handled; 15319c97d46fb57f87ff45d9e6ea7122b4eb21ede8cJeff Brown switch (keyCode) { 15419c97d46fb57f87ff45d9e6ea7122b4eb21ede8cJeff Brown case KeyEvent.KEYCODE_DEL: 15519c97d46fb57f87ff45d9e6ea7122b4eb21ede8cJeff Brown handled = backspace(view, content, keyCode, event); 15619c97d46fb57f87ff45d9e6ea7122b4eb21ede8cJeff Brown break; 15719c97d46fb57f87ff45d9e6ea7122b4eb21ede8cJeff Brown case KeyEvent.KEYCODE_FORWARD_DEL: 15819c97d46fb57f87ff45d9e6ea7122b4eb21ede8cJeff Brown handled = forwardDelete(view, content, keyCode, event); 159474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown break; 160474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown default: 161474dcb5c3ddff737c4ac9fc44a1f7be569605e5fJeff Brown handled = false; 162214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown break; 163214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 164214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 165214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (handled) { 166214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown adjustMetaAfterKeypress(content); 167214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 168214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 169214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown return super.onKeyDown(view, content, keyCode, event); 170214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 171214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 172214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown /** 173214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown * Base implementation handles ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting 174214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown * the event's text into the content. 175214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown */ 176214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown public boolean onKeyOther(View view, Editable content, KeyEvent event) { 177214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (event.getAction() != KeyEvent.ACTION_MULTIPLE 178214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown || event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) { 179214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown // Not something we are interested in. 180214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown return false; 181214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 182214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 183214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown int selectionStart = Selection.getSelectionStart(content); 184214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown int selectionEnd = Selection.getSelectionEnd(content); 185214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (selectionEnd < selectionStart) { 186214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown int temp = selectionEnd; 187214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown selectionEnd = selectionStart; 188214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown selectionStart = temp; 189214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 190214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 191214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown CharSequence text = event.getCharacters(); 192214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown if (text == null) { 193214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown return false; 194214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 195bb3fcba0caf697f1d238a2cbefdf1efe06eded99Jeff Brown 196bb3fcba0caf697f1d238a2cbefdf1efe06eded99Jeff Brown content.replace(selectionStart, selectionEnd, text); 197214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown return true; 198214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown } 199214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown} 200214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown 201214eaf48878bba00cbd5831871bcbd82632b6e34Jeff Brown