diff options
author | 2009-07-15 09:05:23 -0700 | |
---|---|---|
committer | 2009-07-15 09:05:23 -0700 | |
commit | 85d1f158267d64b5660e86fab0baf0432c1dcfbd (patch) | |
tree | 05c7ccd6fe0f43616538366bd52973c4ad22dccd | |
parent | 1f872d4e8675b918dafdd730100df7e865d9ce0b (diff) | |
parent | e3dd884815b2aaeec4241859722ab603e0b1466b (diff) |
Merge change 7353
* changes:
Implement virtual button support.
-rw-r--r-- | include/ui/EventHub.h | 5 | ||||
-rw-r--r-- | libs/ui/EventHub.cpp | 29 | ||||
-rw-r--r-- | services/java/com/android/server/InputDevice.java | 118 | ||||
-rw-r--r-- | services/java/com/android/server/KeyInputQueue.java | 245 | ||||
-rw-r--r-- | services/jni/com_android_server_KeyInputQueue.cpp | 19 |
5 files changed, 348 insertions, 68 deletions
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index e12c4f13ea0d..d9c0af211703 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -73,6 +73,9 @@ public: int getKeycodeState(int key) const; int getKeycodeState(int32_t deviceId, int key) const; + status_t scancodeToKeycode(int32_t deviceId, int scancode, + int32_t* outKeycode, uint32_t* outFlags) const; + // special type codes when devices are added/removed. enum { DEVICE_ADDED = 0x10000000, @@ -121,7 +124,7 @@ private: mutable Mutex mLock; bool mHaveFirstKeyboard; - int32_t mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it + int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it struct device_ent { device_t* device; diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 13c30a795cb2..a72f055c388c 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -240,6 +240,35 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const return 0; } +status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, + int32_t* outKeycode, uint32_t* outFlags) const +{ + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + + if (device != NULL && device->layoutMap != NULL) { + status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); + if (err == NO_ERROR) { + return NO_ERROR; + } + } + + if (mHaveFirstKeyboard) { + device = getDevice(mFirstKeyboardId); + + if (device != NULL && device->layoutMap != NULL) { + status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); + if (err == NO_ERROR) { + return NO_ERROR; + } + } + } + + *outKeycode = 0; + *outFlags = 0; + return NAME_NOT_FOUND; +} + EventHub::device_t* EventHub::getDevice(int32_t deviceId) const { if (deviceId == 0) deviceId = mFirstKeyboardId; diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 9c1f9421a818..a71c39a0b3b5 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -66,19 +66,56 @@ public class InputDevice { MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano, boolean isAbs, Display display, int orientation, int metaState) { - if (!changed) { - return null; - } - float scaledX = x; float scaledY = y; float temp; float scaledPressure = 1.0f; float scaledSize = 0; int edgeFlags = 0; + + int action; + if (down != lastDown) { + if (isAbs) { + final AbsoluteInfo absX = device.absX; + final AbsoluteInfo absY = device.absY; + if (down && absX != null && absY != null) { + // We don't let downs start unless we are + // inside of the screen. There are two reasons for + // this: to avoid spurious touches when holding + // the edges of the device near the touchscreen, + // and to avoid reporting events if there are virtual + // keys on the touchscreen outside of the display + // area. + if (scaledX < absX.minValue || scaledX > absX.maxValue + || scaledY < absY.minValue || scaledY > absY.maxValue) { + if (false) Log.v("InputDevice", "Rejecting (" + scaledX + "," + + scaledY + "): outside of (" + + absX.minValue + "," + absY.minValue + + ")-(" + absX.maxValue + "," + + absY.maxValue + ")"); + return null; + } + } + } else { + x = y = 0; + } + lastDown = down; + if (down) { + action = MotionEvent.ACTION_DOWN; + downTime = curTime; + } else { + action = MotionEvent.ACTION_UP; + } + currentMove = null; + } else { + action = MotionEvent.ACTION_MOVE; + } + if (isAbs) { - int w = display.getWidth()-1; - int h = display.getHeight()-1; + final int dispW = display.getWidth()-1; + final int dispH = display.getHeight()-1; + int w = dispW; + int h = dispH; if (orientation == Surface.ROTATION_90 || orientation == Surface.ROTATION_270) { int tmp = w; @@ -120,16 +157,17 @@ public class InputDevice { break; } - if (scaledX == 0) { - edgeFlags += MotionEvent.EDGE_LEFT; - } else if (scaledX == display.getWidth() - 1.0f) { - edgeFlags += MotionEvent.EDGE_RIGHT; - } - - if (scaledY == 0) { - edgeFlags += MotionEvent.EDGE_TOP; - } else if (scaledY == display.getHeight() - 1.0f) { - edgeFlags += MotionEvent.EDGE_BOTTOM; + if (action != MotionEvent.ACTION_DOWN) { + if (scaledX <= 0) { + edgeFlags += MotionEvent.EDGE_LEFT; + } else if (scaledX >= dispW) { + edgeFlags += MotionEvent.EDGE_RIGHT; + } + if (scaledY <= 0) { + edgeFlags += MotionEvent.EDGE_TOP; + } else if (scaledY >= dispH) { + edgeFlags += MotionEvent.EDGE_BOTTOM; + } } } else { @@ -153,41 +191,25 @@ public class InputDevice { } } - changed = false; - if (down != lastDown) { - int action; - lastDown = down; - if (down) { - action = MotionEvent.ACTION_DOWN; - downTime = curTime; - } else { - action = MotionEvent.ACTION_UP; - } - currentMove = null; - if (!isAbs) { - x = y = 0; - } - return MotionEvent.obtainNano(downTime, curTime, curTimeNano, action, - scaledX, scaledY, scaledPressure, scaledSize, metaState, - xPrecision, yPrecision, device.id, edgeFlags); - } else { - if (currentMove != null) { - if (false) Log.i("InputDevice", "Adding batch x=" + scaledX - + " y=" + scaledY + " to " + currentMove); - currentMove.addBatch(curTime, scaledX, scaledY, - scaledPressure, scaledSize, metaState); - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i("KeyInputQueue", "Updating: " + currentMove); - } - return null; + if (currentMove != null) { + if (false) Log.i("InputDevice", "Adding batch x=" + scaledX + + " y=" + scaledY + " to " + currentMove); + currentMove.addBatch(curTime, scaledX, scaledY, + scaledPressure, scaledSize, metaState); + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i("KeyInputQueue", "Updating: " + currentMove); } - MotionEvent me = MotionEvent.obtainNano(downTime, curTime, curTimeNano, - MotionEvent.ACTION_MOVE, scaledX, scaledY, - scaledPressure, scaledSize, metaState, - xPrecision, yPrecision, device.id, edgeFlags); + return null; + } + + MotionEvent me = MotionEvent.obtainNano(downTime, curTime, + curTimeNano, action, scaledX, scaledY, + scaledPressure, scaledSize, metaState, + xPrecision, yPrecision, device.id, edgeFlags); + if (action == MotionEvent.ACTION_MOVE) { currentMove = me; - return me; } + return me; } } diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index 78cdf8b97eef..fd6b813e7ada 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -30,10 +30,20 @@ import android.view.RawInputEvent; import android.view.Surface; import android.view.WindowManagerPolicy; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + public abstract class KeyInputQueue { static final String TAG = "KeyInputQueue"; - SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>(); + static final boolean DEBUG_VIRTUAL_KEYS = false; + + final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>(); + final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>(); int mGlobalMetaState = 0; boolean mHaveGlobalMetaState = false; @@ -44,10 +54,14 @@ public abstract class KeyInputQueue { int mCacheCount; Display mDisplay = null; + int mDisplayWidth; + int mDisplayHeight; int mOrientation = Surface.ROTATION_0; int[] mKeyRotationMap = null; + VirtualKey mPressedVirtualKey = null; + PowerManager.WakeLock mWakeLock; static final int[] KEY_90_MAP = new int[] { @@ -110,11 +124,106 @@ public abstract class KeyInputQueue { QueuedEvent next; } + /** + * A key that exists as a part of the touch-screen, outside of the normal + * display area of the screen. + */ + static class VirtualKey { + int scancode; + int centerx; + int centery; + int width; + int height; + + int hitLeft; + int hitTop; + int hitRight; + int hitBottom; + + InputDevice lastDevice; + int lastKeycode; + + boolean checkHit(int x, int y) { + return (x >= hitLeft && x <= hitRight + && y >= hitTop && y <= hitBottom); + } + + void computeHitRect(InputDevice dev, int dw, int dh) { + if (dev == lastDevice) { + return; + } + + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode + + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY); + + lastDevice = dev; + + int minx = dev.absX.minValue; + int maxx = dev.absX.maxValue; + + int halfw = width/2; + int left = centerx - halfw; + int right = centerx + halfw; + hitLeft = minx + ((left*maxx-minx)/dw); + hitRight = minx + ((right*maxx-minx)/dw); + + int miny = dev.absY.minValue; + int maxy = dev.absY.maxValue; + + int halfh = height/2; + int top = centery - halfh; + int bottom = centery + halfh; + hitTop = miny + ((top*maxy-miny)/dh); + hitBottom = miny + ((bottom*maxy-miny)/dh); + } + } + KeyInputQueue(Context context) { if (MEASURE_LATENCY) { lt = new LatencyTimer(100, 1000); } + try { + FileInputStream fis = new FileInputStream( + "/sys/board_properties/virtualkeys.synaptics-rmi-touchscreen"); + InputStreamReader isr = new InputStreamReader(fis); + BufferedReader br = new BufferedReader(isr); + String str = br.readLine(); + if (str != null) { + String[] it = str.split(":"); + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it); + final int N = it.length-6; + for (int i=0; i<=N; i+=6) { + if (!"0x01".equals(it[i])) { + Log.w(TAG, "Unknown virtual key type at elem #" + i + + ": " + it[i]); + continue; + } + try { + VirtualKey sb = new VirtualKey(); + sb.scancode = Integer.parseInt(it[i+1]); + sb.centerx = Integer.parseInt(it[i+2]); + sb.centery = Integer.parseInt(it[i+3]); + sb.width = Integer.parseInt(it[i+4]); + sb.height = Integer.parseInt(it[i+5]); + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key " + + sb.scancode + ": center=" + sb.centerx + "," + + sb.centery + " size=" + sb.width + "x" + + sb.height); + mVirtualKeys.add(sb); + } catch (NumberFormatException e) { + Log.w(TAG, "Bad number at region " + i + " in: " + + str, e); + } + } + } + br.close(); + } catch (FileNotFoundException e) { + Log.i(TAG, "No virtual keys found"); + } catch (IOException e) { + Log.w(TAG, "Error reading virtual keys", e); + } + PowerManager pm = (PowerManager)context.getSystemService( Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, @@ -131,6 +240,12 @@ public abstract class KeyInputQueue { public void setDisplay(Display display) { mDisplay = display; + + // We assume at this point that the display dimensions reflect the + // natural, unrotated display. We will perform hit tests for soft + // buttons based on that display. + mDisplayWidth = display.getWidth(); + mDisplayHeight = display.getHeight(); } public void getInputConfiguration(Configuration config) { @@ -173,6 +288,7 @@ public abstract class KeyInputQueue { public static native int getScancodeState(int deviceId, int sw); public static native int getKeycodeState(int sw); public static native int getKeycodeState(int deviceId, int sw); + public static native int scancodeToKeycode(int deviceId, int scancode); public static native boolean hasKeys(int[] keycodes, boolean[] keyExists); public static KeyEvent newKeyEvent(InputDevice device, long downTime, @@ -339,36 +455,127 @@ public abstract class KeyInputQueue { } MotionEvent me; - me = di.mAbs.generateMotion(di, curTime, curTimeNano, true, - mDisplay, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x - + " y=" + di.mAbs.y + " ev=" + me); - if (me != null) { - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i(TAG, "Enqueueing: " + me); + + InputDevice.MotionState ms = di.mAbs; + if (ms.changed) { + ms.changed = false; + + boolean doMotion = true; + + // Look for virtual buttons. + VirtualKey vk = mPressedVirtualKey; + if (vk != null) { + doMotion = false; + if (!ms.down) { + mPressedVirtualKey = null; + ms.lastDown = ms.down; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Generate key up for: " + vk.scancode); + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_KEYBOARD, + newKeyEvent(di, di.mDownTime, + curTime, false, + vk.lastKeycode, + 0, vk.scancode, 0)); + } + } else if (ms.down && !ms.lastDown) { + vk = findSoftButton(di); + if (vk != null) { + doMotion = false; + mPressedVirtualKey = vk; + vk.lastKeycode = scancodeToKeycode( + di.id, vk.scancode); + ms.lastDown = ms.down; + di.mDownTime = curTime; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Generate key down for: " + vk.scancode + + " (keycode=" + vk.lastKeycode + ")"); + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_KEYBOARD, + newKeyEvent(di, di.mDownTime, + curTime, true, + vk.lastKeycode, 0, + vk.scancode, 0)); + } + } + + if (doMotion) { + me = ms.generateMotion(di, curTime, + curTimeNano, true, mDisplay, + mOrientation, mGlobalMetaState); + if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x + + " y=" + di.mAbs.y + " ev=" + me); + if (me != null) { + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i(TAG, "Enqueueing: " + me); + } + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_TOUCHSCREEN, me); + } } - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_TOUCHSCREEN, me); } - me = di.mRel.generateMotion(di, curTime, curTimeNano, false, - mDisplay, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Relative: x=" + di.mRel.x - + " y=" + di.mRel.y + " ev=" + me); - if (me != null) { - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_TRACKBALL, me); + + ms = di.mRel; + if (ms.changed) { + ms.changed = false; + + me = ms.generateMotion(di, curTime, + curTimeNano, false, mDisplay, + mOrientation, mGlobalMetaState); + if (false) Log.v(TAG, "Relative: x=" + di.mRel.x + + " y=" + di.mRel.y + " ev=" + me); + if (me != null) { + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_TRACKBALL, me); + } } } } } } - } - catch (RuntimeException exc) { + + } catch (RuntimeException exc) { Log.e(TAG, "InputReaderThread uncaught exception", exc); } } }; + private VirtualKey findSoftButton(InputDevice dev) { + final int N = mVirtualKeys.size(); + if (N <= 0) { + return null; + } + + final InputDevice.AbsoluteInfo absx = dev.absX; + final InputDevice.AbsoluteInfo absy = dev.absY; + final InputDevice.MotionState absm = dev.mAbs; + if (absx == null || absy == null || absm == null) { + return null; + } + + if (absm.x >= absx.minValue && absm.x <= absx.maxValue + && absm.y >= absy.minValue && absm.y <= absy.maxValue) { + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + absm.x + + "," + absm.y + ") inside of display"); + return null; + } + + for (int i=0; i<N; i++) { + VirtualKey sb = mVirtualKeys.get(i); + sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight); + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" + absm.x + "," + + absm.y + ") in code " + sb.scancode + " - (" + sb.hitLeft + + "," + sb.hitTop + ")-(" + sb.hitRight + "," + + sb.hitBottom + ")"); + if (sb.checkHit(absm.x, absm.y)) { + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!"); + return sb; + } + } + + return null; + } + /** * Returns a new meta state for the given keys and old state. */ diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp index 63830d59c24a..afca1f7ec34f 100644 --- a/services/jni/com_android_server_KeyInputQueue.cpp +++ b/services/jni/com_android_server_KeyInputQueue.cpp @@ -205,6 +205,23 @@ android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz, return st; } +static jint +android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz, + jint deviceId, jint scancode) +{ + jint res = 0; + gLock.lock(); + if (gHub != NULL) { + int32_t keycode; + uint32_t flags; + gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags); + res = keycode; + } + gLock.unlock(); + + return res; +} + static jboolean android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz, jintArray keyCodes, jbooleanArray outFlags) @@ -254,6 +271,8 @@ static JNINativeMethod gInputMethods[] = { (void*) android_server_KeyInputQueue_getKeycodeStateDevice }, { "hasKeys", "([I[Z)Z", (void*) android_server_KeyInputQueue_hasKeys }, + { "scancodeToKeycode", "(II)I", + (void*) android_server_KeyInputQueue_scancodeToKeycode }, }; int register_android_server_KeyInputQueue(JNIEnv* env) |