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