1 /* 2 * Copyright (C) 2007 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 17 package com.android.dumprendertree; 18 19 import android.os.Handler; 20 import android.os.SystemClock; 21 import android.util.*; 22 import android.view.KeyEvent; 23 import android.view.MotionEvent; 24 import android.webkit.WebView; 25 26 import java.lang.InterruptedException; 27 import java.util.Arrays; 28 import java.util.Vector; 29 30 public class WebViewEventSender implements EventSender { 31 32 private static final String LOGTAG = "WebViewEventSender"; 33 34 WebViewEventSender(WebView webView) { 35 mWebView = webView; 36 mTouchPoints = new Vector(); 37 } 38 39 public void resetMouse() { 40 mouseX = mouseY = 0; 41 } 42 43 public void enableDOMUIEventLogging(int DOMNode) { 44 // TODO Auto-generated method stub 45 46 } 47 48 public void fireKeyboardEventsToElement(int DOMNode) { 49 // TODO Auto-generated method stub 50 51 } 52 53 public void keyDown(String character, String[] withModifiers) { 54 Log.e("EventSender", "KeyDown: " + character + "(" 55 + character.getBytes()[0] + ") Modifiers: " 56 + Arrays.toString(withModifiers)); 57 KeyEvent modifier = null; 58 if (withModifiers != null && withModifiers.length > 0) { 59 for (int i = 0; i < withModifiers.length; i++) { 60 int keyCode = modifierMapper(withModifiers[i]); 61 modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); 62 mWebView.onKeyDown(modifier.getKeyCode(), modifier); 63 } 64 } 65 int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]); 66 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); 67 mWebView.onKeyDown(event.getKeyCode(), event); 68 69 } 70 71 public void keyDown(String character) { 72 keyDown(character, null); 73 } 74 75 public void leapForward(int milliseconds) { 76 // TODO Auto-generated method stub 77 78 } 79 80 public void mouseClick() { 81 mouseDown(); 82 mouseUp(); 83 } 84 85 public void mouseDown() { 86 /* KeyEvent event = new KeyEvent( 87 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER); 88 mWebView.onKeyDown(event.getKeyCode(), event); */ 89 } 90 91 public void mouseMoveTo(int X, int Y) { 92 if (X > mouseX) { 93 KeyEvent event = new KeyEvent( 94 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT); 95 mWebView.onKeyDown(event.getKeyCode(), event); 96 mWebView.onKeyUp(event.getKeyCode(), event); 97 } else if ( X < mouseX ) { 98 KeyEvent event = new KeyEvent( 99 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT); 100 mWebView.onKeyDown(event.getKeyCode(), event); 101 mWebView.onKeyUp(event.getKeyCode(), event); 102 } 103 if (Y > mouseY) { 104 KeyEvent event = new KeyEvent( 105 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN); 106 mWebView.onKeyDown(event.getKeyCode(), event); 107 mWebView.onKeyUp(event.getKeyCode(), event); 108 } else if (Y < mouseY ) { 109 KeyEvent event = new KeyEvent( 110 KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP); 111 mWebView.onKeyDown(event.getKeyCode(), event); 112 mWebView.onKeyUp(event.getKeyCode(), event); 113 } 114 mouseX= X; 115 mouseY= Y; 116 117 } 118 119 public void mouseUp() { 120 /* KeyEvent event = new KeyEvent( 121 KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER); 122 mWebView.onKeyDown(event.getKeyCode(), event);*/ 123 124 } 125 126 // Assumes lowercase chars, case needs to be 127 // handled by calling function. 128 static int keyMapper(char c) { 129 // handle numbers 130 if (c >= '0' && c<= '9') { 131 int offset = c - '0'; 132 return KeyEvent.KEYCODE_0 + offset; 133 } 134 135 // handle characters 136 if (c >= 'a' && c <= 'z') { 137 int offset = c - 'a'; 138 return KeyEvent.KEYCODE_A + offset; 139 } 140 141 // handle all others 142 switch (c) { 143 case '*': 144 return KeyEvent.KEYCODE_STAR; 145 case '#': 146 return KeyEvent.KEYCODE_POUND; 147 case ',': 148 return KeyEvent.KEYCODE_COMMA; 149 case '.': 150 return KeyEvent.KEYCODE_PERIOD; 151 case '\t': 152 return KeyEvent.KEYCODE_TAB; 153 case ' ': 154 return KeyEvent.KEYCODE_SPACE; 155 case '\n': 156 return KeyEvent.KEYCODE_ENTER; 157 case '\b': 158 case 0x7F: 159 return KeyEvent.KEYCODE_DEL; 160 case '~': 161 return KeyEvent.KEYCODE_GRAVE; 162 case '-': 163 return KeyEvent.KEYCODE_MINUS; 164 case '=': 165 return KeyEvent.KEYCODE_EQUALS; 166 case '(': 167 return KeyEvent.KEYCODE_LEFT_BRACKET; 168 case ')': 169 return KeyEvent.KEYCODE_RIGHT_BRACKET; 170 case '\\': 171 return KeyEvent.KEYCODE_BACKSLASH; 172 case ';': 173 return KeyEvent.KEYCODE_SEMICOLON; 174 case '\'': 175 return KeyEvent.KEYCODE_APOSTROPHE; 176 case '/': 177 return KeyEvent.KEYCODE_SLASH; 178 default: 179 break; 180 } 181 182 return c; 183 } 184 185 static int modifierMapper(String modifier) { 186 if (modifier.equals("ctrlKey")) { 187 return KeyEvent.KEYCODE_ALT_LEFT; 188 } else if (modifier.equals("shiftKey")) { 189 return KeyEvent.KEYCODE_SHIFT_LEFT; 190 } else if (modifier.equals("altKey")) { 191 return KeyEvent.KEYCODE_SYM; 192 } else if (modifier.equals("metaKey")) { 193 return KeyEvent.KEYCODE_UNKNOWN; 194 } 195 return KeyEvent.KEYCODE_UNKNOWN; 196 } 197 198 public void touchStart() { 199 // We only support single touch so examine the first touch point only. 200 // If multi touch is enabled in the future, we need to re-examine this to send 201 // all the touch points with the event. 202 TouchPoint tp = mTouchPoints.get(0); 203 204 if (tp == null) { 205 return; 206 } 207 208 tp.setDownTime(SystemClock.uptimeMillis()); 209 MotionEvent event = MotionEvent.obtain(tp.downTime(), tp.downTime(), 210 MotionEvent.ACTION_DOWN, tp.getX(), tp.getY(), mTouchMetaState); 211 mWebView.onTouchEvent(event); 212 } 213 214 public void touchMove() { 215 TouchPoint tp = mTouchPoints.get(0); 216 217 if (tp == null) { 218 return; 219 } 220 221 if (!tp.hasMoved()) { 222 return; 223 } 224 225 MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(), 226 MotionEvent.ACTION_MOVE, tp.getX(), tp.getY(), mTouchMetaState); 227 mWebView.onTouchEvent(event); 228 229 tp.setMoved(false); 230 } 231 232 public void touchEnd() { 233 TouchPoint tp = mTouchPoints.get(0); 234 235 if (tp == null) { 236 return; 237 } 238 239 MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(), 240 MotionEvent.ACTION_UP, tp.getX(), tp.getY(), mTouchMetaState); 241 mWebView.onTouchEvent(event); 242 243 if (tp.isReleased()) { 244 mTouchPoints.remove(0); 245 } 246 } 247 248 public void touchCancel() { 249 TouchPoint tp = mTouchPoints.get(0); 250 if (tp == null) { 251 return; 252 } 253 254 if (tp.cancelled()) { 255 MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(), 256 MotionEvent.ACTION_CANCEL, tp.getX(), tp.getY(), mTouchMetaState); 257 mWebView.onTouchEvent(event); 258 } 259 } 260 261 public void cancelTouchPoint(int id) { 262 TouchPoint tp = mTouchPoints.get(0); 263 if (tp == null) { 264 return; 265 } 266 267 tp.cancel(); 268 } 269 270 public void addTouchPoint(int x, int y) { 271 mTouchPoints.add(new TouchPoint(contentsToWindowX(x), contentsToWindowY(y))); 272 if (mTouchPoints.size() > 1) { 273 Log.w(LOGTAG, "Adding more than one touch point, but multi touch is not supported!"); 274 } 275 } 276 277 public void updateTouchPoint(int id, int x, int y) { 278 TouchPoint tp = mTouchPoints.get(0); 279 if (tp == null) { 280 return; 281 } 282 283 tp.update(contentsToWindowX(x), contentsToWindowY(y)); 284 tp.setMoved(true); 285 } 286 287 public void setTouchModifier(String modifier, boolean enabled) { 288 int mask = 0; 289 if ("alt".equals(modifier.toLowerCase())) { 290 mask = KeyEvent.META_ALT_ON; 291 } else if ("shift".equals(modifier.toLowerCase())) { 292 mask = KeyEvent.META_SHIFT_ON; 293 } else if ("ctrl".equals(modifier.toLowerCase())) { 294 mask = KeyEvent.META_SYM_ON; 295 } 296 297 if (enabled) { 298 mTouchMetaState |= mask; 299 } else { 300 mTouchMetaState &= ~mask; 301 } 302 } 303 304 public void releaseTouchPoint(int id) { 305 TouchPoint tp = mTouchPoints.get(0); 306 if (tp == null) { 307 return; 308 } 309 310 tp.release(); 311 } 312 313 public void clearTouchPoints() { 314 mTouchPoints.clear(); 315 } 316 317 public void clearTouchMetaState() { 318 mTouchMetaState = 0; 319 } 320 321 private int contentsToWindowX(int x) { 322 return (int) (x * mWebView.getScale()) - mWebView.getScrollX(); 323 } 324 325 private int contentsToWindowY(int y) { 326 return (int) (y * mWebView.getScale()) - mWebView.getScrollY(); 327 } 328 329 private WebView mWebView = null; 330 private int mouseX; 331 private int mouseY; 332 333 private class TouchPoint { 334 private int mX; 335 private int mY; 336 private long mDownTime; 337 private boolean mReleased; 338 private boolean mMoved; 339 private boolean mCancelled; 340 341 public TouchPoint(int x, int y) { 342 mX = x; 343 mY = y; 344 mReleased = false; 345 mMoved = false; 346 mCancelled = false; 347 } 348 349 public void setDownTime(long downTime) { mDownTime = downTime; } 350 public long downTime() { return mDownTime; } 351 public void cancel() { mCancelled = true; } 352 353 public boolean cancelled() { return mCancelled; } 354 355 public void release() { mReleased = true; } 356 public boolean isReleased() { return mReleased; } 357 358 public void setMoved(boolean moved) { mMoved = moved; } 359 public boolean hasMoved() { return mMoved; } 360 361 public int getX() { return mX; } 362 public int getY() { return mY; } 363 364 public void update(int x, int y) { 365 mX = x; 366 mY = y; 367 } 368 }; 369 370 private Vector<TouchPoint> mTouchPoints; 371 private int mTouchMetaState; 372 } 373