blob: f62c7ee53c1d91510f82765e3d4784786fd338dc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package com.android.server;
18
19import android.content.Context;
20import android.content.res.Configuration;
Adam Powellf5bcc6a2010-03-02 10:42:16 -080021import android.content.res.Resources;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040022import android.os.Environment;
Michael Chan53071d62009-05-13 17:29:48 -070023import android.os.LatencyTimer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.os.PowerManager;
Michael Chan53071d62009-05-13 17:29:48 -070025import android.os.SystemClock;
Dianne Hackborna2e92262010-03-02 17:19:29 -080026import android.os.SystemProperties;
Joe Onorato8a9b2202010-02-26 18:56:32 -080027import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.SparseArray;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040029import android.util.Xml;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.view.Display;
31import android.view.KeyEvent;
32import android.view.MotionEvent;
33import android.view.RawInputEvent;
34import android.view.Surface;
35import android.view.WindowManagerPolicy;
36
Dianne Hackborn2269d1572010-02-24 19:54:22 -080037import com.android.internal.util.XmlUtils;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040038
39import org.xmlpull.v1.XmlPullParser;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040040
Dianne Hackborne3dd8842009-07-14 12:06:54 -070041import java.io.BufferedReader;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040042import java.io.File;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070043import java.io.FileInputStream;
44import java.io.FileNotFoundException;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040045import java.io.FileReader;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070046import java.io.IOException;
47import java.io.InputStreamReader;
Dianne Hackborna2e92262010-03-02 17:19:29 -080048import java.io.PrintWriter;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070049import java.util.ArrayList;
50
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051public abstract class KeyInputQueue {
52 static final String TAG = "KeyInputQueue";
53
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070054 static final boolean DEBUG = false;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070055 static final boolean DEBUG_VIRTUAL_KEYS = false;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070056 static final boolean DEBUG_POINTERS = false;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070057
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070058 /**
59 * Turn on some hacks we have to improve the touch interaction with a
60 * certain device whose screen currently is not all that good.
61 */
Dianne Hackborn65cb605e2009-11-10 17:06:22 -080062 static boolean BAD_TOUCH_HACK = false;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -070063
Adam Powellf5bcc6a2010-03-02 10:42:16 -080064 /**
65 * Turn on some hacks to improve touch interaction with another device
66 * where touch coordinate data can get corrupted.
67 */
68 static boolean JUMPY_TOUCH_HACK = false;
69
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040070 private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
71
Dianne Hackborne3dd8842009-07-14 12:06:54 -070072 final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
Dianne Hackborna8f60182009-09-01 19:01:50 -070073 final SparseArray<InputDevice> mIgnoredDevices = new SparseArray<InputDevice>();
Dianne Hackborne3dd8842009-07-14 12:06:54 -070074 final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
Dianne Hackbornddca3ee2009-07-23 19:01:31 -070075 final HapticFeedbackCallback mHapticFeedbackCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076
77 int mGlobalMetaState = 0;
78 boolean mHaveGlobalMetaState = false;
79
80 final QueuedEvent mFirst;
81 final QueuedEvent mLast;
82 QueuedEvent mCache;
83 int mCacheCount;
84
85 Display mDisplay = null;
Dianne Hackborne3dd8842009-07-14 12:06:54 -070086 int mDisplayWidth;
87 int mDisplayHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89 int mOrientation = Surface.ROTATION_0;
90 int[] mKeyRotationMap = null;
91
Dianne Hackborne3dd8842009-07-14 12:06:54 -070092 VirtualKey mPressedVirtualKey = null;
93
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 PowerManager.WakeLock mWakeLock;
95
96 static final int[] KEY_90_MAP = new int[] {
97 KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
98 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP,
99 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT,
100 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN,
101 };
102
103 static final int[] KEY_180_MAP = new int[] {
104 KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP,
105 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT,
106 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
107 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
108 };
109
110 static final int[] KEY_270_MAP = new int[] {
111 KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
112 KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP,
113 KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT,
114 KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN,
115 };
116
117 public static final int FILTER_REMOVE = 0;
118 public static final int FILTER_KEEP = 1;
119 public static final int FILTER_ABORT = -1;
Michael Chan53071d62009-05-13 17:29:48 -0700120
121 private static final boolean MEASURE_LATENCY = false;
122 private LatencyTimer lt;
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 public interface FilterCallback {
125 int filterEvent(QueuedEvent ev);
126 }
127
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700128 public interface HapticFeedbackCallback {
129 void virtualKeyFeedback(KeyEvent event);
130 }
131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 static class QueuedEvent {
133 InputDevice inputDevice;
Michael Chan53071d62009-05-13 17:29:48 -0700134 long whenNano;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 int flags; // From the raw event
136 int classType; // One of the class constants in InputEvent
137 Object event;
138 boolean inQueue;
139
140 void copyFrom(QueuedEvent that) {
141 this.inputDevice = that.inputDevice;
Michael Chan53071d62009-05-13 17:29:48 -0700142 this.whenNano = that.whenNano;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 this.flags = that.flags;
144 this.classType = that.classType;
145 this.event = that.event;
146 }
147
148 @Override
149 public String toString() {
150 return "QueuedEvent{"
151 + Integer.toHexString(System.identityHashCode(this))
152 + " " + event + "}";
153 }
154
155 // not copied
156 QueuedEvent prev;
157 QueuedEvent next;
158 }
159
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700160 /**
161 * A key that exists as a part of the touch-screen, outside of the normal
162 * display area of the screen.
163 */
164 static class VirtualKey {
165 int scancode;
166 int centerx;
167 int centery;
168 int width;
169 int height;
170
171 int hitLeft;
172 int hitTop;
173 int hitRight;
174 int hitBottom;
175
176 InputDevice lastDevice;
177 int lastKeycode;
178
179 boolean checkHit(int x, int y) {
180 return (x >= hitLeft && x <= hitRight
181 && y >= hitTop && y <= hitBottom);
182 }
183
184 void computeHitRect(InputDevice dev, int dw, int dh) {
185 if (dev == lastDevice) {
186 return;
187 }
188
Joe Onorato8a9b2202010-02-26 18:56:32 -0800189 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "computeHitRect for " + scancode
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700190 + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
191
192 lastDevice = dev;
193
194 int minx = dev.absX.minValue;
195 int maxx = dev.absX.maxValue;
196
197 int halfw = width/2;
198 int left = centerx - halfw;
199 int right = centerx + halfw;
200 hitLeft = minx + ((left*maxx-minx)/dw);
201 hitRight = minx + ((right*maxx-minx)/dw);
202
203 int miny = dev.absY.minValue;
204 int maxy = dev.absY.maxValue;
205
206 int halfh = height/2;
207 int top = centery - halfh;
208 int bottom = centery + halfh;
209 hitTop = miny + ((top*maxy-miny)/dh);
210 hitBottom = miny + ((bottom*maxy-miny)/dh);
211 }
212 }
Michael Chan53071d62009-05-13 17:29:48 -0700213
Iliyan Malchev75b2aed2009-08-06 14:50:57 -0700214 private void readVirtualKeys(String deviceName) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700215 try {
216 FileInputStream fis = new FileInputStream(
Iliyan Malchev75b2aed2009-08-06 14:50:57 -0700217 "/sys/board_properties/virtualkeys." + deviceName);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700218 InputStreamReader isr = new InputStreamReader(fis);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -0700219 BufferedReader br = new BufferedReader(isr, 2048);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700220 String str = br.readLine();
221 if (str != null) {
222 String[] it = str.split(":");
Joe Onorato8a9b2202010-02-26 18:56:32 -0800223 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700224 final int N = it.length-6;
225 for (int i=0; i<=N; i+=6) {
226 if (!"0x01".equals(it[i])) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800227 Slog.w(TAG, "Unknown virtual key type at elem #" + i
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700228 + ": " + it[i]);
229 continue;
230 }
231 try {
232 VirtualKey sb = new VirtualKey();
233 sb.scancode = Integer.parseInt(it[i+1]);
234 sb.centerx = Integer.parseInt(it[i+2]);
235 sb.centery = Integer.parseInt(it[i+3]);
236 sb.width = Integer.parseInt(it[i+4]);
237 sb.height = Integer.parseInt(it[i+5]);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800238 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700239 + sb.scancode + ": center=" + sb.centerx + ","
240 + sb.centery + " size=" + sb.width + "x"
241 + sb.height);
242 mVirtualKeys.add(sb);
243 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800244 Slog.w(TAG, "Bad number at region " + i + " in: "
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700245 + str, e);
246 }
247 }
248 }
249 br.close();
250 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800251 Slog.i(TAG, "No virtual keys found");
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700252 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800253 Slog.w(TAG, "Error reading virtual keys", e);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700254 }
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400255 }
256
257 private void readExcludedDevices() {
258 // Read partner-provided list of excluded input devices
259 XmlPullParser parser = null;
260 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
261 File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
262 FileReader confreader = null;
263 try {
264 confreader = new FileReader(confFile);
265 parser = Xml.newPullParser();
266 parser.setInput(confreader);
267 XmlUtils.beginDocument(parser, "devices");
268
269 while (true) {
270 XmlUtils.nextElement(parser);
271 if (!"device".equals(parser.getName())) {
272 break;
273 }
274 String name = parser.getAttributeValue(null, "name");
275 if (name != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800276 if (DEBUG) Slog.v(TAG, "addExcludedDevice " + name);
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400277 addExcludedDevice(name);
278 }
279 }
280 } catch (FileNotFoundException e) {
281 // It's ok if the file does not exist.
282 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800283 Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400284 } finally {
285 try { if (confreader != null) confreader.close(); } catch (IOException e) { }
286 }
287 }
288
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700289 KeyInputQueue(Context context, HapticFeedbackCallback hapticFeedbackCallback) {
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400290 if (MEASURE_LATENCY) {
291 lt = new LatencyTimer(100, 1000);
292 }
293
Adam Powellf5bcc6a2010-03-02 10:42:16 -0800294 Resources r = context.getResources();
295 BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
296
297 JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
Dianne Hackborn65cb605e2009-11-10 17:06:22 -0800298
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700299 mHapticFeedbackCallback = hapticFeedbackCallback;
300
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700301 if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
302 readExcludedDevices();
303 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 PowerManager pm = (PowerManager)context.getSystemService(
306 Context.POWER_SERVICE);
307 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
308 "KeyInputQueue");
309 mWakeLock.setReferenceCounted(false);
310
311 mFirst = new QueuedEvent();
312 mLast = new QueuedEvent();
313 mFirst.next = mLast;
314 mLast.prev = mFirst;
315
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700316 if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
317 mThread.start();
318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
320
321 public void setDisplay(Display display) {
322 mDisplay = display;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700323
324 // We assume at this point that the display dimensions reflect the
325 // natural, unrotated display. We will perform hit tests for soft
326 // buttons based on that display.
327 mDisplayWidth = display.getWidth();
328 mDisplayHeight = display.getHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 }
330
331 public void getInputConfiguration(Configuration config) {
332 synchronized (mFirst) {
333 config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
334 config.keyboard = Configuration.KEYBOARD_NOKEYS;
335 config.navigation = Configuration.NAVIGATION_NONAV;
336
337 final int N = mDevices.size();
338 for (int i=0; i<N; i++) {
339 InputDevice d = mDevices.valueAt(i);
340 if (d != null) {
341 if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
342 config.touchscreen
343 = Configuration.TOUCHSCREEN_FINGER;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800344 //Slog.i("foo", "***** HAVE TOUCHSCREEN!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 }
346 if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
347 config.keyboard
348 = Configuration.KEYBOARD_QWERTY;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800349 //Slog.i("foo", "***** HAVE QWERTY!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 }
351 if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
352 config.navigation
353 = Configuration.NAVIGATION_TRACKBALL;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800354 //Slog.i("foo", "***** HAVE TRACKBALL!");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700355 } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
356 config.navigation
357 = Configuration.NAVIGATION_DPAD;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800358 //Slog.i("foo", "***** HAVE DPAD!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 }
360 }
361 }
362 }
363 }
364
Dianne Hackborn6af0d502009-09-28 13:25:46 -0700365 public int getScancodeState(int code) {
366 synchronized (mFirst) {
367 VirtualKey vk = mPressedVirtualKey;
368 if (vk != null) {
369 if (vk.scancode == code) {
370 return 2;
371 }
372 }
373 return nativeGetScancodeState(code);
374 }
375 }
376
377 public int getScancodeState(int deviceId, int code) {
378 synchronized (mFirst) {
379 VirtualKey vk = mPressedVirtualKey;
380 if (vk != null) {
381 if (vk.scancode == code) {
382 return 2;
383 }
384 }
385 return nativeGetScancodeState(deviceId, code);
386 }
387 }
388
Dianne Hackborn1d62ea92009-11-17 12:49:50 -0800389 public int getTrackballScancodeState(int code) {
390 synchronized (mFirst) {
391 final int N = mDevices.size();
392 for (int i=0; i<N; i++) {
393 InputDevice dev = mDevices.valueAt(i);
394 if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
395 int res = nativeGetScancodeState(dev.id, code);
396 if (res > 0) {
397 return res;
398 }
399 }
400 }
401 }
402
403 return 0;
404 }
405
406 public int getDPadScancodeState(int code) {
407 synchronized (mFirst) {
408 final int N = mDevices.size();
409 for (int i=0; i<N; i++) {
410 InputDevice dev = mDevices.valueAt(i);
411 if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
412 int res = nativeGetScancodeState(dev.id, code);
413 if (res > 0) {
414 return res;
415 }
416 }
417 }
418 }
419
420 return 0;
421 }
422
Dianne Hackborn6af0d502009-09-28 13:25:46 -0700423 public int getKeycodeState(int code) {
424 synchronized (mFirst) {
425 VirtualKey vk = mPressedVirtualKey;
426 if (vk != null) {
427 if (vk.lastKeycode == code) {
428 return 2;
429 }
430 }
431 return nativeGetKeycodeState(code);
432 }
433 }
434
435 public int getKeycodeState(int deviceId, int code) {
436 synchronized (mFirst) {
437 VirtualKey vk = mPressedVirtualKey;
438 if (vk != null) {
439 if (vk.lastKeycode == code) {
440 return 2;
441 }
442 }
443 return nativeGetKeycodeState(deviceId, code);
444 }
445 }
446
Dianne Hackborn1d62ea92009-11-17 12:49:50 -0800447 public int getTrackballKeycodeState(int code) {
448 synchronized (mFirst) {
449 final int N = mDevices.size();
450 for (int i=0; i<N; i++) {
451 InputDevice dev = mDevices.valueAt(i);
452 if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
453 int res = nativeGetKeycodeState(dev.id, code);
454 if (res > 0) {
455 return res;
456 }
457 }
458 }
459 }
460
461 return 0;
462 }
463
464 public int getDPadKeycodeState(int code) {
465 synchronized (mFirst) {
466 final int N = mDevices.size();
467 for (int i=0; i<N; i++) {
468 InputDevice dev = mDevices.valueAt(i);
469 if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
470 int res = nativeGetKeycodeState(dev.id, code);
471 if (res > 0) {
472 return res;
473 }
474 }
475 }
476 }
477
478 return 0;
479 }
480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 public static native String getDeviceName(int deviceId);
482 public static native int getDeviceClasses(int deviceId);
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400483 public static native void addExcludedDevice(String deviceName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 public static native boolean getAbsoluteInfo(int deviceId, int axis,
485 InputDevice.AbsoluteInfo outInfo);
486 public static native int getSwitchState(int sw);
487 public static native int getSwitchState(int deviceId, int sw);
Dianne Hackborn6af0d502009-09-28 13:25:46 -0700488 public static native int nativeGetScancodeState(int code);
489 public static native int nativeGetScancodeState(int deviceId, int code);
490 public static native int nativeGetKeycodeState(int code);
491 public static native int nativeGetKeycodeState(int deviceId, int code);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700492 public static native int scancodeToKeycode(int deviceId, int scancode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
494
495 public static KeyEvent newKeyEvent(InputDevice device, long downTime,
496 long eventTime, boolean down, int keycode, int repeatCount,
497 int scancode, int flags) {
498 return new KeyEvent(
499 downTime, eventTime,
500 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
501 keycode, repeatCount,
502 device != null ? device.mMetaKeysState : 0,
503 device != null ? device.id : -1, scancode,
The Android Open Source Project10592532009-03-18 17:39:46 -0700504 flags | KeyEvent.FLAG_FROM_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 }
506
507 Thread mThread = new Thread("InputDeviceReader") {
508 public void run() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800509 if (DEBUG) Slog.v(TAG, "InputDeviceReader.run()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 android.os.Process.setThreadPriority(
511 android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
512
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700513 RawInputEvent ev = new RawInputEvent();
514 while (true) {
515 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 InputDevice di;
517
518 // block, doesn't release the monitor
519 readEvent(ev);
520
521 boolean send = false;
522 boolean configChanged = false;
523
524 if (false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800525 Slog.i(TAG, "Input event: dev=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 + Integer.toHexString(ev.deviceId)
527 + " type=0x" + Integer.toHexString(ev.type)
528 + " scancode=" + ev.scancode
529 + " keycode=" + ev.keycode
530 + " value=" + ev.value);
531 }
532
533 if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
534 synchronized (mFirst) {
535 di = newInputDevice(ev.deviceId);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700536 if (di.classes != 0) {
537 // If this device is some kind of input class,
538 // we care about it.
539 mDevices.put(ev.deviceId, di);
540 if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
541 readVirtualKeys(di.name);
542 }
543 // The configuration may have changed because
544 // of this device.
545 configChanged = true;
546 } else {
547 // We won't do anything with this device.
548 mIgnoredDevices.put(ev.deviceId, di);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800549 Slog.i(TAG, "Ignoring non-input device: id=0x"
Dianne Hackborna8f60182009-09-01 19:01:50 -0700550 + Integer.toHexString(di.id)
551 + ", name=" + di.name);
Iliyan Malchev75b2aed2009-08-06 14:50:57 -0700552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
554 } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
555 synchronized (mFirst) {
Dianne Hackborna8f60182009-09-01 19:01:50 -0700556 if (false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800557 Slog.i(TAG, "Device removed: id=0x"
Dianne Hackborna8f60182009-09-01 19:01:50 -0700558 + Integer.toHexString(ev.deviceId));
559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 di = mDevices.get(ev.deviceId);
561 if (di != null) {
562 mDevices.delete(ev.deviceId);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700563 // The configuration may have changed because
564 // of this device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 configChanged = true;
Dianne Hackborna8f60182009-09-01 19:01:50 -0700566 } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
567 mIgnoredDevices.remove(ev.deviceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800569 Slog.w(TAG, "Removing bad device id: "
Dianne Hackborna8f60182009-09-01 19:01:50 -0700570 + Integer.toHexString(ev.deviceId));
571 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 }
573 }
574 } else {
575 di = getInputDevice(ev.deviceId);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700576 if (di == null) {
577 // This may be some junk from an ignored device.
578 continue;
579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580
581 // first crack at it
582 send = preprocessEvent(di, ev);
583
584 if (ev.type == RawInputEvent.EV_KEY) {
585 di.mMetaKeysState = makeMetaState(ev.keycode,
586 ev.value != 0, di.mMetaKeysState);
587 mHaveGlobalMetaState = false;
588 }
589 }
590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 if (configChanged) {
592 synchronized (mFirst) {
Michael Chan53071d62009-05-13 17:29:48 -0700593 addLocked(di, System.nanoTime(), 0,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 RawInputEvent.CLASS_CONFIGURATION_CHANGED,
595 null);
596 }
597 }
598
599 if (!send) {
600 continue;
601 }
602
603 synchronized (mFirst) {
604 // NOTE: The event timebase absolutely must be the same
605 // timebase as SystemClock.uptimeMillis().
606 //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
607 final long curTime = SystemClock.uptimeMillis();
Michael Chan53071d62009-05-13 17:29:48 -0700608 final long curTimeNano = System.nanoTime();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800609 //Slog.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610
611 final int classes = di.classes;
612 final int type = ev.type;
613 final int scancode = ev.scancode;
614 send = false;
615
616 // Is it a key event?
617 if (type == RawInputEvent.EV_KEY &&
618 (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
619 (scancode < RawInputEvent.BTN_FIRST ||
620 scancode > RawInputEvent.BTN_LAST)) {
621 boolean down;
622 if (ev.value != 0) {
623 down = true;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700624 di.mKeyDownTime = curTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 } else {
626 down = false;
627 }
628 int keycode = rotateKeyCodeLocked(ev.keycode);
Michael Chan53071d62009-05-13 17:29:48 -0700629 addLocked(di, curTimeNano, ev.flags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 RawInputEvent.CLASS_KEYBOARD,
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700631 newKeyEvent(di, di.mKeyDownTime, curTime, down,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 keycode, 0, scancode,
633 ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
634 ? KeyEvent.FLAG_WOKE_HERE : 0));
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 } else if (ev.type == RawInputEvent.EV_KEY) {
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700637 // Single touch protocol: touch going down or up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 if (ev.scancode == RawInputEvent.BTN_TOUCH &&
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700639 (classes&(RawInputEvent.CLASS_TOUCHSCREEN
640 |RawInputEvent.CLASS_TOUCHSCREEN_MT))
641 == RawInputEvent.CLASS_TOUCHSCREEN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 di.mAbs.changed = true;
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700643 di.mAbs.mDown[0] = ev.value != 0;
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700644
645 // Trackball (mouse) protocol: press down or up.
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700646 } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
648 di.mRel.changed = true;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700649 di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 send = true;
651 }
652
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700653 // Process position events from multitouch protocol.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 } else if (ev.type == RawInputEvent.EV_ABS &&
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700655 (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
656 if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
657 di.mAbs.changed = true;
658 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
659 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
660 } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
661 di.mAbs.changed = true;
662 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
663 + MotionEvent.SAMPLE_X] = ev.value;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800664 if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700665 + di.mAbs.mAddingPointerOffset
666 + " X:" + ev.value);
667 } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
668 di.mAbs.changed = true;
669 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
670 + MotionEvent.SAMPLE_Y] = ev.value;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800671 if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700672 + di.mAbs.mAddingPointerOffset
673 + " Y:" + ev.value);
674 } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
675 di.mAbs.changed = true;
676 di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
677 + MotionEvent.SAMPLE_SIZE] = ev.value;
678 }
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700679
680 // Process position events from single touch protocol.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700681 } else if (ev.type == RawInputEvent.EV_ABS &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
683 if (ev.scancode == RawInputEvent.ABS_X) {
684 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700685 di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 } else if (ev.scancode == RawInputEvent.ABS_Y) {
687 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700688 di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
690 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700691 di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
692 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700693 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
695 di.mAbs.changed = true;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700696 di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
697 di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700698 + MotionEvent.SAMPLE_SIZE] = ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 }
700
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700701 // Process movement events from trackball (mouse) protocol.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 } else if (ev.type == RawInputEvent.EV_REL &&
703 (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
704 // Add this relative movement into our totals.
705 if (ev.scancode == RawInputEvent.REL_X) {
706 di.mRel.changed = true;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700707 di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 } else if (ev.scancode == RawInputEvent.REL_Y) {
709 di.mRel.changed = true;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700710 di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 }
712 }
713
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700714 // Handle multitouch protocol sync: tells us that the
715 // driver has returned all data for -one- of the pointers
716 // that is currently down.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700717 if (ev.type == RawInputEvent.EV_SYN
718 && ev.scancode == RawInputEvent.SYN_MT_REPORT
719 && di.mAbs != null) {
720 di.mAbs.changed = true;
721 if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
722 // If the value is <= 0, the pointer is not
723 // down, so keep it in the count.
724
725 if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
726 + MotionEvent.SAMPLE_PRESSURE] != 0) {
727 final int num = di.mAbs.mNextNumPointers+1;
728 di.mAbs.mNextNumPointers = num;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800729 if (DEBUG_POINTERS) Slog.v(TAG,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700730 "MT_REPORT: now have " + num + " pointers");
731 final int newOffset = (num <= InputDevice.MAX_POINTERS)
732 ? (num * MotionEvent.NUM_SAMPLE_DATA)
733 : (InputDevice.MAX_POINTERS *
734 MotionEvent.NUM_SAMPLE_DATA);
735 di.mAbs.mAddingPointerOffset = newOffset;
736 di.mAbs.mNextData[newOffset
737 + MotionEvent.SAMPLE_PRESSURE] = 0;
738 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800739 if (DEBUG_POINTERS) Slog.v(TAG, "MT_REPORT: no pointer");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700740 }
741 }
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700742
743 // Handle general event sync: all data for the current
744 // event update has been delivered.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700745 } else if (send || (ev.type == RawInputEvent.EV_SYN
746 && ev.scancode == RawInputEvent.SYN_REPORT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 if (mDisplay != null) {
748 if (!mHaveGlobalMetaState) {
749 computeGlobalMetaStateLocked();
750 }
751
752 MotionEvent me;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700753
754 InputDevice.MotionState ms = di.mAbs;
755 if (ms.changed) {
Dianne Hackborna2e92262010-03-02 17:19:29 -0800756 ms.everChanged = true;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700757 ms.changed = false;
758
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700759 if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
760 |RawInputEvent.CLASS_TOUCHSCREEN_MT))
761 == RawInputEvent.CLASS_TOUCHSCREEN) {
762 ms.mNextNumPointers = 0;
Dianne Hackborn2a2b34432009-08-12 17:13:55 -0700763 if (ms.mDown[0]) {
764 System.arraycopy(di.curTouchVals, 0,
765 ms.mNextData, 0,
766 MotionEvent.NUM_SAMPLE_DATA);
767 ms.mNextNumPointers++;
768 }
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700769 }
770
771 if (BAD_TOUCH_HACK) {
772 ms.dropBadPoint(di);
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700773 }
Adam Powellf5bcc6a2010-03-02 10:42:16 -0800774 if (JUMPY_TOUCH_HACK) {
775 ms.dropJumpyPoint(di);
776 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700777
778 boolean doMotion = !monitorVirtualKey(di,
779 ev, curTime, curTimeNano);
780
781 if (doMotion && ms.mNextNumPointers > 0
Dianne Hackborndc953722009-10-19 11:24:39 -0700782 && (ms.mLastNumPointers == 0
783 || ms.mSkipLastPointers)) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700784 doMotion = !generateVirtualKeyDown(di,
785 ev, curTime, curTimeNano);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700787
788 if (doMotion) {
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700789 // XXX Need to be able to generate
790 // multiple events here, for example
791 // if two fingers change up/down state
792 // at the same time.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700793 do {
794 me = ms.generateAbsMotion(di, curTime,
795 curTimeNano, mDisplay,
796 mOrientation, mGlobalMetaState);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800797 if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700798 + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
799 + " y="
800 + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
801 + " ev=" + me);
802 if (me != null) {
803 if (WindowManagerPolicy.WATCH_POINTER) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800804 Slog.i(TAG, "Enqueueing: " + me);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700805 }
806 addLocked(di, curTimeNano, ev.flags,
807 RawInputEvent.CLASS_TOUCHSCREEN, me);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700808 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700809 } while (ms.hasMore());
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700810 } else {
811 // We are consuming movement in the
812 // virtual key area... but still
813 // propagate this to the previous
814 // data for comparisons.
Dianne Hackbornf2ddfb12009-10-13 22:43:33 -0700815 int num = ms.mNextNumPointers;
816 if (num > InputDevice.MAX_POINTERS) {
817 num = InputDevice.MAX_POINTERS;
818 }
Dianne Hackborn1411d1c2009-10-12 23:21:18 -0700819 System.arraycopy(ms.mNextData, 0,
820 ms.mLastData, 0,
Dianne Hackbornf2ddfb12009-10-13 22:43:33 -0700821 num * MotionEvent.NUM_SAMPLE_DATA);
822 ms.mLastNumPointers = num;
Dianne Hackborndc953722009-10-19 11:24:39 -0700823 ms.mSkipLastPointers = true;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700824 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700825
826 ms.finish();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700828
829 ms = di.mRel;
830 if (ms.changed) {
Dianne Hackborna2e92262010-03-02 17:19:29 -0800831 ms.everChanged = true;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700832 ms.changed = false;
833
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700834 me = ms.generateRelMotion(di, curTime,
835 curTimeNano,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700836 mOrientation, mGlobalMetaState);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800837 if (false) Slog.v(TAG, "Relative: x="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700838 + di.mRel.mNextData[MotionEvent.SAMPLE_X]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700839 + " y="
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700840 + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700841 + " ev=" + me);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700842 if (me != null) {
843 addLocked(di, curTimeNano, ev.flags,
844 RawInputEvent.CLASS_TRACKBALL, me);
845 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847 }
848 }
849 }
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700850
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700851 } catch (RuntimeException exc) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800852 Slog.e(TAG, "InputReaderThread uncaught exception", exc);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855 }
856 };
857
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700858 private boolean isInsideDisplay(InputDevice dev) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700859 final InputDevice.AbsoluteInfo absx = dev.absX;
860 final InputDevice.AbsoluteInfo absy = dev.absY;
861 final InputDevice.MotionState absm = dev.mAbs;
862 if (absx == null || absy == null || absm == null) {
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700863 return true;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700864 }
865
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700866 if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
867 && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
868 && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
869 && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800870 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Input ("
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700871 + absm.mNextData[MotionEvent.SAMPLE_X]
872 + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700873 + ") inside of display");
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700874 return true;
875 }
876
877 return false;
878 }
879
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700880 private VirtualKey findVirtualKey(InputDevice dev) {
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700881 final int N = mVirtualKeys.size();
882 if (N <= 0) {
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700883 return null;
884 }
885
Dianne Hackbornddca3ee2009-07-23 19:01:31 -0700886 final InputDevice.MotionState absm = dev.mAbs;
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700887 for (int i=0; i<N; i++) {
888 VirtualKey sb = mVirtualKeys.get(i);
889 sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800890 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit test ("
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700891 + absm.mNextData[MotionEvent.SAMPLE_X] + ","
892 + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
Dianne Hackborn9822d2b2009-07-20 17:33:15 -0700893 + sb.scancode + " - (" + sb.hitLeft
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700894 + "," + sb.hitTop + ")-(" + sb.hitRight + ","
895 + sb.hitBottom + ")");
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700896 if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
897 absm.mNextData[MotionEvent.SAMPLE_Y])) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800898 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit!");
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700899 return sb;
900 }
901 }
902
903 return null;
904 }
905
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700906 private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
907 long curTime, long curTimeNano) {
908 if (isInsideDisplay(di)) {
909 // Didn't consume event.
910 return false;
911 }
912
913
914 VirtualKey vk = findVirtualKey(di);
915 if (vk != null) {
916 final InputDevice.MotionState ms = di.mAbs;
917 mPressedVirtualKey = vk;
918 vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
919 ms.mLastNumPointers = ms.mNextNumPointers;
920 di.mKeyDownTime = curTime;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800921 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700922 "Generate key down for: " + vk.scancode
923 + " (keycode=" + vk.lastKeycode + ")");
924 KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
925 vk.lastKeycode, 0, vk.scancode,
926 KeyEvent.FLAG_VIRTUAL_HARD_KEY);
927 mHapticFeedbackCallback.virtualKeyFeedback(event);
928 addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
929 event);
930 }
931
932 // We always consume the event, even if we didn't
933 // generate a key event. There are two reasons for
934 // this: to avoid spurious touches when holding
935 // the edges of the device near the touchscreen,
936 // and to avoid reporting events if there are virtual
937 // keys on the touchscreen outside of the display
938 // area.
939 // Note that for all of this we are only looking at the
940 // first pointer, since what we are handling here is the
941 // first pointer going down, and this is the coordinate
942 // that will be used to dispatch the event.
943 if (false) {
944 final InputDevice.AbsoluteInfo absx = di.absX;
945 final InputDevice.AbsoluteInfo absy = di.absY;
946 final InputDevice.MotionState absm = di.mAbs;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800947 Slog.v(TAG, "Rejecting ("
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700948 + absm.mNextData[MotionEvent.SAMPLE_X] + ","
949 + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
950 + absx.minValue + "," + absy.minValue
951 + ")-(" + absx.maxValue + ","
952 + absx.maxValue + ")");
953 }
954 return true;
955 }
956
957 private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
958 long curTime, long curTimeNano) {
959 VirtualKey vk = mPressedVirtualKey;
960 if (vk == null) {
961 return false;
962 }
963
964 final InputDevice.MotionState ms = di.mAbs;
965 if (ms.mNextNumPointers <= 0) {
966 mPressedVirtualKey = null;
967 ms.mLastNumPointers = 0;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800968 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Generate key up for: " + vk.scancode);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700969 KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
970 vk.lastKeycode, 0, vk.scancode,
971 KeyEvent.FLAG_VIRTUAL_HARD_KEY);
972 mHapticFeedbackCallback.virtualKeyFeedback(event);
973 addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
974 event);
975 return true;
976
977 } else if (isInsideDisplay(di)) {
978 // Whoops the pointer has moved into
979 // the display area! Cancel the
980 // virtual key and start a pointer
981 // motion.
982 mPressedVirtualKey = null;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800983 if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Cancel key up for: " + vk.scancode);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700984 KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
985 vk.lastKeycode, 0, vk.scancode,
986 KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
987 mHapticFeedbackCallback.virtualKeyFeedback(event);
988 addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
989 event);
990 ms.mLastNumPointers = 0;
991 return false;
992 }
993
994 return true;
995 }
996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 /**
998 * Returns a new meta state for the given keys and old state.
999 */
1000 private static final int makeMetaState(int keycode, boolean down, int old) {
1001 int mask;
1002 switch (keycode) {
1003 case KeyEvent.KEYCODE_ALT_LEFT:
1004 mask = KeyEvent.META_ALT_LEFT_ON;
1005 break;
1006 case KeyEvent.KEYCODE_ALT_RIGHT:
1007 mask = KeyEvent.META_ALT_RIGHT_ON;
1008 break;
1009 case KeyEvent.KEYCODE_SHIFT_LEFT:
1010 mask = KeyEvent.META_SHIFT_LEFT_ON;
1011 break;
1012 case KeyEvent.KEYCODE_SHIFT_RIGHT:
1013 mask = KeyEvent.META_SHIFT_RIGHT_ON;
1014 break;
1015 case KeyEvent.KEYCODE_SYM:
1016 mask = KeyEvent.META_SYM_ON;
1017 break;
1018 default:
1019 return old;
1020 }
1021 int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)
1022 & (down ? (old | mask) : (old & ~mask));
1023 if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) {
1024 result |= KeyEvent.META_ALT_ON;
1025 }
1026 if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) {
1027 result |= KeyEvent.META_SHIFT_ON;
1028 }
1029 return result;
1030 }
1031
1032 private void computeGlobalMetaStateLocked() {
1033 int i = mDevices.size();
1034 mGlobalMetaState = 0;
1035 while ((--i) >= 0) {
1036 mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState;
1037 }
1038 mHaveGlobalMetaState = true;
1039 }
1040
1041 /*
1042 * Return true if you want the event to get passed on to the
1043 * rest of the system, and false if you've handled it and want
1044 * it dropped.
1045 */
1046 abstract boolean preprocessEvent(InputDevice device, RawInputEvent event);
1047
1048 InputDevice getInputDevice(int deviceId) {
1049 synchronized (mFirst) {
1050 return getInputDeviceLocked(deviceId);
1051 }
1052 }
1053
1054 private InputDevice getInputDeviceLocked(int deviceId) {
1055 return mDevices.get(deviceId);
1056 }
1057
1058 public void setOrientation(int orientation) {
1059 synchronized(mFirst) {
1060 mOrientation = orientation;
1061 switch (orientation) {
1062 case Surface.ROTATION_90:
1063 mKeyRotationMap = KEY_90_MAP;
1064 break;
1065 case Surface.ROTATION_180:
1066 mKeyRotationMap = KEY_180_MAP;
1067 break;
1068 case Surface.ROTATION_270:
1069 mKeyRotationMap = KEY_270_MAP;
1070 break;
1071 default:
1072 mKeyRotationMap = null;
1073 break;
1074 }
1075 }
1076 }
1077
1078 public int rotateKeyCode(int keyCode) {
1079 synchronized(mFirst) {
1080 return rotateKeyCodeLocked(keyCode);
1081 }
1082 }
1083
1084 private int rotateKeyCodeLocked(int keyCode) {
1085 int[] map = mKeyRotationMap;
1086 if (map != null) {
1087 final int N = map.length;
1088 for (int i=0; i<N; i+=2) {
1089 if (map[i] == keyCode) {
1090 return map[i+1];
1091 }
1092 }
1093 }
1094 return keyCode;
1095 }
1096
1097 boolean hasEvents() {
1098 synchronized (mFirst) {
1099 return mFirst.next != mLast;
1100 }
1101 }
1102
1103 /*
1104 * returns true if we returned an event, and false if we timed out
1105 */
1106 QueuedEvent getEvent(long timeoutMS) {
1107 long begin = SystemClock.uptimeMillis();
1108 final long end = begin+timeoutMS;
1109 long now = begin;
1110 synchronized (mFirst) {
1111 while (mFirst.next == mLast && end > now) {
1112 try {
1113 mWakeLock.release();
1114 mFirst.wait(end-now);
1115 }
1116 catch (InterruptedException e) {
1117 }
1118 now = SystemClock.uptimeMillis();
1119 if (begin > now) {
1120 begin = now;
1121 }
1122 }
1123 if (mFirst.next == mLast) {
1124 return null;
1125 }
1126 QueuedEvent p = mFirst.next;
1127 mFirst.next = p.next;
1128 mFirst.next.prev = mFirst;
1129 p.inQueue = false;
1130 return p;
1131 }
1132 }
1133
Dianne Hackborn83fe3f52009-09-12 23:38:30 -07001134 /**
1135 * Return true if the queue has an up event pending that corresponds
1136 * to the same key as the given key event.
1137 */
1138 boolean hasKeyUpEvent(KeyEvent origEvent) {
1139 synchronized (mFirst) {
1140 final int keyCode = origEvent.getKeyCode();
1141 QueuedEvent cur = mLast.prev;
1142 while (cur.prev != null) {
1143 if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
1144 KeyEvent ke = (KeyEvent)cur.event;
1145 if (ke.getAction() == KeyEvent.ACTION_UP
1146 && ke.getKeyCode() == keyCode) {
1147 return true;
1148 }
1149 }
1150 cur = cur.prev;
1151 }
1152 }
1153
1154 return false;
1155 }
1156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 void recycleEvent(QueuedEvent ev) {
1158 synchronized (mFirst) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001159 //Slog.i(TAG, "Recycle event: " + ev);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 if (ev.event == ev.inputDevice.mAbs.currentMove) {
1161 ev.inputDevice.mAbs.currentMove = null;
1162 }
1163 if (ev.event == ev.inputDevice.mRel.currentMove) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001164 if (false) Slog.i(TAG, "Detach rel " + ev.event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 ev.inputDevice.mRel.currentMove = null;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -07001166 ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
1167 ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 }
1169 recycleLocked(ev);
1170 }
1171 }
1172
1173 void filterQueue(FilterCallback cb) {
1174 synchronized (mFirst) {
1175 QueuedEvent cur = mLast.prev;
1176 while (cur.prev != null) {
1177 switch (cb.filterEvent(cur)) {
1178 case FILTER_REMOVE:
1179 cur.prev.next = cur.next;
1180 cur.next.prev = cur.prev;
1181 break;
1182 case FILTER_ABORT:
1183 return;
1184 }
1185 cur = cur.prev;
1186 }
1187 }
1188 }
1189
Michael Chan53071d62009-05-13 17:29:48 -07001190 private QueuedEvent obtainLocked(InputDevice device, long whenNano,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 int flags, int classType, Object event) {
1192 QueuedEvent ev;
1193 if (mCacheCount == 0) {
1194 ev = new QueuedEvent();
1195 } else {
1196 ev = mCache;
1197 ev.inQueue = false;
1198 mCache = ev.next;
1199 mCacheCount--;
1200 }
1201 ev.inputDevice = device;
Michael Chan53071d62009-05-13 17:29:48 -07001202 ev.whenNano = whenNano;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 ev.flags = flags;
1204 ev.classType = classType;
1205 ev.event = event;
1206 return ev;
1207 }
1208
1209 private void recycleLocked(QueuedEvent ev) {
1210 if (ev.inQueue) {
1211 throw new RuntimeException("Event already in queue!");
1212 }
1213 if (mCacheCount < 10) {
1214 mCacheCount++;
1215 ev.next = mCache;
1216 mCache = ev;
1217 ev.inQueue = true;
1218 }
1219 }
1220
Michael Chan53071d62009-05-13 17:29:48 -07001221 private void addLocked(InputDevice device, long whenNano, int flags,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 int classType, Object event) {
1223 boolean poke = mFirst.next == mLast;
1224
Michael Chan53071d62009-05-13 17:29:48 -07001225 QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 QueuedEvent p = mLast.prev;
Michael Chan53071d62009-05-13 17:29:48 -07001227 while (p != mFirst && ev.whenNano < p.whenNano) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 p = p.prev;
1229 }
1230
1231 ev.next = p.next;
1232 ev.prev = p;
1233 p.next = ev;
1234 ev.next.prev = ev;
1235 ev.inQueue = true;
1236
1237 if (poke) {
Michael Chan53071d62009-05-13 17:29:48 -07001238 long time;
1239 if (MEASURE_LATENCY) {
1240 time = System.nanoTime();
1241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 mFirst.notify();
1243 mWakeLock.acquire();
Michael Chan53071d62009-05-13 17:29:48 -07001244 if (MEASURE_LATENCY) {
1245 lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
1246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
1248 }
1249
1250 private InputDevice newInputDevice(int deviceId) {
1251 int classes = getDeviceClasses(deviceId);
1252 String name = getDeviceName(deviceId);
Dianne Hackborna8f60182009-09-01 19:01:50 -07001253 InputDevice.AbsoluteInfo absX = null;
1254 InputDevice.AbsoluteInfo absY = null;
1255 InputDevice.AbsoluteInfo absPressure = null;
1256 InputDevice.AbsoluteInfo absSize = null;
1257 if (classes != 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001258 Slog.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
Dianne Hackborna8f60182009-09-01 19:01:50 -07001259 + ", name=" + name
1260 + ", classes=" + Integer.toHexString(classes));
1261 if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
1262 absX = loadAbsoluteInfo(deviceId,
1263 RawInputEvent.ABS_MT_POSITION_X, "X");
1264 absY = loadAbsoluteInfo(deviceId,
1265 RawInputEvent.ABS_MT_POSITION_Y, "Y");
1266 absPressure = loadAbsoluteInfo(deviceId,
1267 RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
1268 absSize = loadAbsoluteInfo(deviceId,
1269 RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
1270 } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
1271 absX = loadAbsoluteInfo(deviceId,
1272 RawInputEvent.ABS_X, "X");
1273 absY = loadAbsoluteInfo(deviceId,
1274 RawInputEvent.ABS_Y, "Y");
1275 absPressure = loadAbsoluteInfo(deviceId,
1276 RawInputEvent.ABS_PRESSURE, "Pressure");
1277 absSize = loadAbsoluteInfo(deviceId,
1278 RawInputEvent.ABS_TOOL_WIDTH, "Size");
1279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281
1282 return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
1283 }
1284
1285 private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel,
1286 String name) {
1287 InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
1288 if (getAbsoluteInfo(id, channel, info)
1289 && info.minValue != info.maxValue) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001290 Slog.i(TAG, " " + name + ": min=" + info.minValue
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 + " max=" + info.maxValue
1292 + " flat=" + info.flat
1293 + " fuzz=" + info.fuzz);
1294 info.range = info.maxValue-info.minValue;
1295 return info;
1296 }
Joe Onorato8a9b2202010-02-26 18:56:32 -08001297 Slog.i(TAG, " " + name + ": unknown values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 return null;
1299 }
1300 private static native boolean readEvent(RawInputEvent outEvent);
Dianne Hackborna2e92262010-03-02 17:19:29 -08001301
1302 void dump(PrintWriter pw, String prefix) {
1303 synchronized (mFirst) {
1304 for (int i=0; i<mDevices.size(); i++) {
1305 InputDevice dev = mDevices.valueAt(i);
1306 pw.print(prefix); pw.print("Device #");
1307 pw.print(mDevices.keyAt(i)); pw.print(" ");
1308 pw.print(dev.name); pw.print(" (classes=0x");
1309 pw.print(Integer.toHexString(dev.classes));
1310 pw.println("):");
1311 pw.print(prefix); pw.print(" mKeyDownTime=");
1312 pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
1313 pw.println(dev.mMetaKeysState);
1314 if (dev.absX != null) {
1315 pw.print(prefix); pw.print(" absX: "); dev.absX.dump(pw);
1316 pw.println("");
1317 }
1318 if (dev.absY != null) {
1319 pw.print(prefix); pw.print(" absY: "); dev.absY.dump(pw);
1320 pw.println("");
1321 }
1322 if (dev.absPressure != null) {
1323 pw.print(prefix); pw.print(" absPressure: ");
1324 dev.absPressure.dump(pw); pw.println("");
1325 }
1326 if (dev.absSize != null) {
1327 pw.print(prefix); pw.print(" absSize: ");
1328 dev.absSize.dump(pw); pw.println("");
1329 }
1330 if (dev.mAbs.everChanged) {
1331 pw.print(prefix); pw.println(" mAbs:");
1332 dev.mAbs.dump(pw, prefix + " ");
1333 }
1334 if (dev.mRel.everChanged) {
1335 pw.print(prefix); pw.println(" mRel:");
1336 dev.mRel.dump(pw, prefix + " ");
1337 }
1338 }
1339 pw.println(" ");
1340 for (int i=0; i<mIgnoredDevices.size(); i++) {
1341 InputDevice dev = mIgnoredDevices.valueAt(i);
1342 pw.print(prefix); pw.print("Ignored Device #");
1343 pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
1344 pw.print(dev.name); pw.print(" (classes=0x");
1345 pw.print(Integer.toHexString(dev.classes));
1346 pw.println(")");
1347 }
1348 pw.println(" ");
1349 for (int i=0; i<mVirtualKeys.size(); i++) {
1350 VirtualKey vk = mVirtualKeys.get(i);
1351 pw.print(prefix); pw.print("Virtual Key #");
1352 pw.print(i); pw.println(":");
1353 pw.print(prefix); pw.print(" scancode="); pw.println(vk.scancode);
1354 pw.print(prefix); pw.print(" centerx="); pw.print(vk.centerx);
1355 pw.print(" centery="); pw.print(vk.centery);
1356 pw.print(" width="); pw.print(vk.width);
1357 pw.print(" height="); pw.println(vk.height);
1358 pw.print(prefix); pw.print(" hitLeft="); pw.print(vk.hitLeft);
1359 pw.print(" hitTop="); pw.print(vk.hitTop);
1360 pw.print(" hitRight="); pw.print(vk.hitRight);
1361 pw.print(" hitBottom="); pw.println(vk.hitBottom);
1362 if (vk.lastDevice != null) {
1363 pw.print(prefix); pw.print(" lastDevice=#");
1364 pw.println(vk.lastDevice.id);
1365 }
1366 if (vk.lastKeycode != 0) {
1367 pw.print(prefix); pw.print(" lastKeycode=");
1368 pw.println(vk.lastKeycode);
1369 }
1370 }
1371 pw.println(" ");
1372 pw.print(prefix); pw.print(" Default keyboard: ");
1373 pw.println(SystemProperties.get("hw.keyboards.0.devname"));
1374 pw.print(prefix); pw.print(" mGlobalMetaState=");
1375 pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
1376 pw.println(mHaveGlobalMetaState);
1377 pw.print(prefix); pw.print(" mDisplayWidth=");
1378 pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
1379 pw.println(mDisplayHeight);
1380 pw.print(prefix); pw.print(" mOrientation=");
1381 pw.println(mOrientation);
1382 if (mPressedVirtualKey != null) {
1383 pw.print(prefix); pw.print(" mPressedVirtualKey.scancode=");
1384 pw.println(mPressedVirtualKey.scancode);
1385 }
1386 }
1387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388}