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