blob: 63607fa34872e7285787c84b73e0045985cbaa26 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.text.method;
18
19import android.view.KeyEvent;
20import android.view.View;
21import android.text.*;
22import android.text.method.TextKeyListener.Capitalize;
23import android.widget.TextView;
24
Jeff Brown6b53e8d2010-11-10 16:03:06 -080025/**
26 * Abstract base class for key listeners.
27 *
28 * Provides a basic foundation for entering and editing text.
29 * Subclasses should override {@link #onKeyDown} and {@link #onKeyUp} to insert
30 * characters as keys are pressed.
Jean Chalard405bc512012-05-29 19:12:34 +090031 * <p></p>
32 * As for all implementations of {@link KeyListener}, this class is only concerned
33 * with hardware keyboards. Software input methods have no obligation to trigger
34 * the methods in this class.
Jeff Brown6b53e8d2010-11-10 16:03:06 -080035 */
36public abstract class BaseKeyListener extends MetaKeyKeyListener
37 implements KeyListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
39
40 /**
Jeff Brown14d0ca12010-12-21 16:06:44 -080041 * Performs the action that happens when you press the {@link KeyEvent#KEYCODE_DEL} key in
42 * a {@link TextView}. If there is a selection, deletes the selection; otherwise,
43 * deletes the character before the cursor, if any; ALT+DEL deletes everything on
44 * the line the cursor is on.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 *
Jeff Brown6b53e8d2010-11-10 16:03:06 -080046 * @return true if anything was deleted; false otherwise.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 */
Jeff Brown14d0ca12010-12-21 16:06:44 -080048 public boolean backspace(View view, Editable content, int keyCode, KeyEvent event) {
Jeff Brownd1724712011-02-26 14:32:13 -080049 return backspaceOrForwardDelete(view, content, keyCode, event, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 }
51
Jeff Brown14d0ca12010-12-21 16:06:44 -080052 /**
53 * Performs the action that happens when you press the {@link KeyEvent#KEYCODE_FORWARD_DEL}
54 * key in a {@link TextView}. If there is a selection, deletes the selection; otherwise,
55 * deletes the character before the cursor, if any; ALT+FORWARD_DEL deletes everything on
56 * the line the cursor is on.
57 *
58 * @return true if anything was deleted; false otherwise.
59 */
60 public boolean forwardDelete(View view, Editable content, int keyCode, KeyEvent event) {
Jeff Brownd1724712011-02-26 14:32:13 -080061 return backspaceOrForwardDelete(view, content, keyCode, event, true);
62 }
63
64 private boolean backspaceOrForwardDelete(View view, Editable content, int keyCode,
65 KeyEvent event, boolean isForwardDelete) {
66 // Ensure the key event does not have modifiers except ALT or SHIFT.
67 if (!KeyEvent.metaStateHasNoModifiers(event.getMetaState()
68 & ~(KeyEvent.META_SHIFT_MASK | KeyEvent.META_ALT_MASK))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 return false;
70 }
71
Jeff Brownd1724712011-02-26 14:32:13 -080072 // If there is a current selection, delete it.
Jeff Brown14d0ca12010-12-21 16:06:44 -080073 if (deleteSelection(view, content)) {
74 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 }
76
Jeff Brownd1724712011-02-26 14:32:13 -080077 // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
Jean Chalard8a1597b2013-03-04 18:45:12 -080078 if (getMetaState(content, META_ALT_ON, event) == 1) {
Jeff Brownd1724712011-02-26 14:32:13 -080079 if (deleteLine(view, content)) {
80 return true;
81 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 }
83
Jeff Brownd1724712011-02-26 14:32:13 -080084 // Delete a character.
Jeff Brown14d0ca12010-12-21 16:06:44 -080085 final int start = Selection.getSelectionEnd(content);
Jeff Brownd1724712011-02-26 14:32:13 -080086 final int end;
87 if (isForwardDelete || event.isShiftPressed()
88 || getMetaState(content, META_SHIFT_ON) == 1) {
89 end = TextUtils.getOffsetAfter(content, start);
90 } else {
91 end = TextUtils.getOffsetBefore(content, start);
92 }
Jeff Brown14d0ca12010-12-21 16:06:44 -080093 if (start != end) {
94 content.delete(Math.min(start, end), Math.max(start, end));
95 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 }
Jeff Brown14d0ca12010-12-21 16:06:44 -080097 return false;
98 }
99
100 private boolean deleteSelection(View view, Editable content) {
101 int selectionStart = Selection.getSelectionStart(content);
102 int selectionEnd = Selection.getSelectionEnd(content);
103 if (selectionEnd < selectionStart) {
104 int temp = selectionEnd;
105 selectionEnd = selectionStart;
106 selectionStart = temp;
107 }
108 if (selectionStart != selectionEnd) {
109 content.delete(selectionStart, selectionEnd);
110 return true;
111 }
112 return false;
113 }
114
115 private boolean deleteLine(View view, Editable content) {
116 if (view instanceof TextView) {
117 final Layout layout = ((TextView) view).getLayout();
118 if (layout != null) {
119 final int line = layout.getLineForOffset(Selection.getSelectionStart(content));
120 final int start = layout.getLineStart(line);
121 final int end = layout.getLineEnd(line);
122 if (end != start) {
123 content.delete(start, end);
124 return true;
125 }
126 }
127 }
128 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
130
131 static int makeTextContentType(Capitalize caps, boolean autoText) {
132 int contentType = InputType.TYPE_CLASS_TEXT;
133 switch (caps) {
134 case CHARACTERS:
135 contentType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
136 break;
137 case WORDS:
138 contentType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
139 break;
140 case SENTENCES:
141 contentType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
142 break;
143 }
144 if (autoText) {
145 contentType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
146 }
147 return contentType;
148 }
Jeff Brown14d0ca12010-12-21 16:06:44 -0800149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 public boolean onKeyDown(View view, Editable content,
151 int keyCode, KeyEvent event) {
Jeff Brown14d0ca12010-12-21 16:06:44 -0800152 boolean handled;
153 switch (keyCode) {
154 case KeyEvent.KEYCODE_DEL:
155 handled = backspace(view, content, keyCode, event);
156 break;
157 case KeyEvent.KEYCODE_FORWARD_DEL:
158 handled = forwardDelete(view, content, keyCode, event);
159 break;
160 default:
161 handled = false;
162 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 }
Jeff Brown14d0ca12010-12-21 16:06:44 -0800164
165 if (handled) {
166 adjustMetaAfterKeypress(content);
167 }
168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 return super.onKeyDown(view, content, keyCode, event);
170 }
Jeff Brown14d0ca12010-12-21 16:06:44 -0800171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /**
173 * Base implementation handles ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting
174 * the event's text into the content.
175 */
176 public boolean onKeyOther(View view, Editable content, KeyEvent event) {
177 if (event.getAction() != KeyEvent.ACTION_MULTIPLE
178 || event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) {
179 // Not something we are interested in.
180 return false;
181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
Jeff Brown14d0ca12010-12-21 16:06:44 -0800183 int selectionStart = Selection.getSelectionStart(content);
184 int selectionEnd = Selection.getSelectionEnd(content);
185 if (selectionEnd < selectionStart) {
186 int temp = selectionEnd;
187 selectionEnd = selectionStart;
188 selectionStart = temp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
190
191 CharSequence text = event.getCharacters();
192 if (text == null) {
193 return false;
194 }
Jeff Brown14d0ca12010-12-21 16:06:44 -0800195
196 content.replace(selectionStart, selectionEnd, text);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 return true;
198 }
199}
200