ArrowKeyMovementMethod.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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 17package android.text.method; 18 19import android.util.Log; 20import android.view.KeyEvent; 21import android.text.*; 22import android.widget.TextView; 23import android.view.View; 24import android.view.MotionEvent; 25 26// XXX this doesn't extend MetaKeyKeyListener because the signatures 27// don't match. Need to figure that out. Meanwhile the meta keys 28// won't work in fields that don't take input. 29 30public class 31ArrowKeyMovementMethod 32implements MovementMethod 33{ 34 private boolean up(TextView widget, Spannable buffer) { 35 boolean cap = (MetaKeyKeyListener.getMetaState(buffer, 36 KeyEvent.META_SHIFT_ON) == 1) || 37 (MetaKeyKeyListener.getMetaState(buffer, 38 MetaKeyKeyListener.META_SELECTING) != 0); 39 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 40 KeyEvent.META_ALT_ON) == 1; 41 Layout layout = widget.getLayout(); 42 43 if (cap) { 44 if (alt) { 45 Selection.extendSelection(buffer, 0); 46 return true; 47 } else { 48 return Selection.extendUp(buffer, layout); 49 } 50 } else { 51 if (alt) { 52 Selection.setSelection(buffer, 0); 53 return true; 54 } else { 55 return Selection.moveUp(buffer, layout); 56 } 57 } 58 } 59 60 private boolean down(TextView widget, Spannable buffer) { 61 boolean cap = (MetaKeyKeyListener.getMetaState(buffer, 62 KeyEvent.META_SHIFT_ON) == 1) || 63 (MetaKeyKeyListener.getMetaState(buffer, 64 MetaKeyKeyListener.META_SELECTING) != 0); 65 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 66 KeyEvent.META_ALT_ON) == 1; 67 Layout layout = widget.getLayout(); 68 69 if (cap) { 70 if (alt) { 71 Selection.extendSelection(buffer, buffer.length()); 72 return true; 73 } else { 74 return Selection.extendDown(buffer, layout); 75 } 76 } else { 77 if (alt) { 78 Selection.setSelection(buffer, buffer.length()); 79 return true; 80 } else { 81 return Selection.moveDown(buffer, layout); 82 } 83 } 84 } 85 86 private boolean left(TextView widget, Spannable buffer) { 87 boolean cap = (MetaKeyKeyListener.getMetaState(buffer, 88 KeyEvent.META_SHIFT_ON) == 1) || 89 (MetaKeyKeyListener.getMetaState(buffer, 90 MetaKeyKeyListener.META_SELECTING) != 0); 91 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 92 KeyEvent.META_ALT_ON) == 1; 93 Layout layout = widget.getLayout(); 94 95 if (cap) { 96 if (alt) { 97 return Selection.extendToLeftEdge(buffer, layout); 98 } else { 99 return Selection.extendLeft(buffer, layout); 100 } 101 } else { 102 if (alt) { 103 return Selection.moveToLeftEdge(buffer, layout); 104 } else { 105 return Selection.moveLeft(buffer, layout); 106 } 107 } 108 } 109 110 private boolean right(TextView widget, Spannable buffer) { 111 boolean cap = (MetaKeyKeyListener.getMetaState(buffer, 112 KeyEvent.META_SHIFT_ON) == 1) || 113 (MetaKeyKeyListener.getMetaState(buffer, 114 MetaKeyKeyListener.META_SELECTING) != 0); 115 boolean alt = MetaKeyKeyListener.getMetaState(buffer, 116 KeyEvent.META_ALT_ON) == 1; 117 Layout layout = widget.getLayout(); 118 119 if (cap) { 120 if (alt) { 121 return Selection.extendToRightEdge(buffer, layout); 122 } else { 123 return Selection.extendRight(buffer, layout); 124 } 125 } else { 126 if (alt) { 127 return Selection.moveToRightEdge(buffer, layout); 128 } else { 129 return Selection.moveRight(buffer, layout); 130 } 131 } 132 } 133 134 public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 135 if (executeDown(widget, buffer, keyCode)) { 136 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); 137 MetaKeyKeyListener.resetLockedMeta(buffer); 138 return true; 139 } 140 141 return false; 142 } 143 144 private boolean executeDown(TextView widget, Spannable buffer, int keyCode) { 145 boolean handled = false; 146 147 switch (keyCode) { 148 case KeyEvent.KEYCODE_DPAD_UP: 149 handled |= up(widget, buffer); 150 break; 151 152 case KeyEvent.KEYCODE_DPAD_DOWN: 153 handled |= down(widget, buffer); 154 break; 155 156 case KeyEvent.KEYCODE_DPAD_LEFT: 157 handled |= left(widget, buffer); 158 break; 159 160 case KeyEvent.KEYCODE_DPAD_RIGHT: 161 handled |= right(widget, buffer); 162 break; 163 164 case KeyEvent.KEYCODE_DPAD_CENTER: 165 if (MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0) { 166 if (widget.showContextMenu()) { 167 handled = true; 168 } 169 } 170 } 171 172 if (handled) { 173 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); 174 MetaKeyKeyListener.resetLockedMeta(buffer); 175 } 176 177 return handled; 178 } 179 180 public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode, KeyEvent event) { 181 return false; 182 } 183 184 public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) { 185 int code = event.getKeyCode(); 186 if (code != KeyEvent.KEYCODE_UNKNOWN 187 && event.getAction() == KeyEvent.ACTION_MULTIPLE) { 188 int repeat = event.getRepeatCount(); 189 boolean handled = false; 190 while ((--repeat) > 0) { 191 handled |= executeDown(view, text, code); 192 } 193 return handled; 194 } 195 return false; 196 } 197 198 public boolean onTrackballEvent(TextView widget, Spannable text, 199 MotionEvent event) { 200 return false; 201 } 202 203 public boolean onTouchEvent(TextView widget, Spannable buffer, 204 MotionEvent event) { 205 boolean handled = Touch.onTouchEvent(widget, buffer, event); 206 207 if (widget.isFocused()) { 208 if (event.getAction() == MotionEvent.ACTION_UP) { 209 int x = (int) event.getX(); 210 int y = (int) event.getY(); 211 212 x -= widget.getTotalPaddingLeft(); 213 y -= widget.getTotalPaddingTop(); 214 215 x += widget.getScrollX(); 216 y += widget.getScrollY(); 217 218 Layout layout = widget.getLayout(); 219 int line = layout.getLineForVertical(y); 220 int off = layout.getOffsetForHorizontal(line, x); 221 222 boolean cap = (MetaKeyKeyListener.getMetaState(buffer, 223 KeyEvent.META_SHIFT_ON) == 1) || 224 (MetaKeyKeyListener.getMetaState(buffer, 225 MetaKeyKeyListener.META_SELECTING) != 0); 226 227 if (cap) { 228 Selection.extendSelection(buffer, off); 229 } else { 230 Selection.setSelection(buffer, off); 231 } 232 233 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); 234 MetaKeyKeyListener.resetLockedMeta(buffer); 235 236 return true; 237 } 238 } 239 240 return handled; 241 } 242 243 public boolean canSelectArbitrarily() { 244 return true; 245 } 246 247 public void initialize(TextView widget, Spannable text) { 248 Selection.setSelection(text, 0); 249 } 250 251 public void onTakeFocus(TextView view, Spannable text, int dir) { 252 if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) { 253 Layout layout = view.getLayout(); 254 255 if (layout == null) { 256 /* 257 * This shouldn't be null, but do something sensible if it is. 258 */ 259 Selection.setSelection(text, text.length()); 260 } else { 261 /* 262 * Put the cursor at the end of the first line, which is 263 * either the last offset if there is only one line, or the 264 * offset before the first character of the second line 265 * if there is more than one line. 266 */ 267 if (layout.getLineCount() == 1) { 268 Selection.setSelection(text, text.length()); 269 } else { 270 Selection.setSelection(text, layout.getLineStart(1) - 1); 271 } 272 } 273 } else { 274 Selection.setSelection(text, text.length()); 275 } 276 } 277 278 public static MovementMethod getInstance() { 279 if (sInstance == null) 280 sInstance = new ArrowKeyMovementMethod(); 281 282 return sInstance; 283 } 284 285 private static ArrowKeyMovementMethod sInstance; 286} 287